improve chat messages list view

fix auto scroll when receiving new message #LINQT-2154
This commit is contained in:
Gaelle Braud 2025-11-24 18:37:42 +01:00
parent 29691485bf
commit a7ba374b8f
9 changed files with 304 additions and 210 deletions

View file

@ -96,10 +96,12 @@ void EventLogList::setChatCore(QSharedPointer<ChatCore> core) {
[event](const QSharedPointer<EventLogCore> item) { return item == event; }); [event](const QSharedPointer<EventLogCore> item) { return item == event; });
if (it == eventsList.end()) { if (it == eventsList.end()) {
connectItem(event); connectItem(event);
add(event); prepend(event);
int index; int index;
get(event.get(), &index); get(event.get(), &index);
emit eventInserted(index, new EventLogGui(event)); if (event->getChatMessageCore() && !event->getChatMessageCore()->isRemoteMessage()) {
emit eventInsertedByUser(index);
}
} }
} }
}); });
@ -122,6 +124,13 @@ void EventLogList::setDisplayItemsStep(int displayItemsStep) {
} }
} }
void EventLogList::markIndexAsRead(int index) {
if (index < mList.count()) {
auto eventLog = mList[index].objectCast<EventLogCore>();
if (eventLog && eventLog->getChatMessageCore()) eventLog->getChatMessageCore()->lMarkAsRead();
}
}
void EventLogList::displayMore() { void EventLogList::displayMore() {
auto loadMoreItems = [this] { auto loadMoreItems = [this] {
if (!mChatCore) return; if (!mChatCore) return;
@ -139,7 +148,7 @@ void EventLogList::displayMore() {
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, chatModel->getMonitor()); auto model = EventLogCore::create(it, chatModel->getMonitor());
events->push_back(model); if (it->getChatMessage() || model->isHandled()) events->push_front(model);
} }
mCoreModelConnection->invokeToCore([this, events] { mCoreModelConnection->invokeToCore([this, events] {
int currentCount = mList.count(); int currentCount = mList.count();
@ -147,8 +156,8 @@ void EventLogList::displayMore() {
for (int i = events->size() - 1; i >= 0; --i) { for (int i = events->size() - 1; i >= 0; --i) {
const auto &ev = events->at(i); const auto &ev = events->at(i);
connectItem(ev); connectItem(ev);
prepend(ev);
} }
add(*events);
} }
}); });
}); });
@ -166,8 +175,10 @@ void EventLogList::displayMore() {
void EventLogList::loadMessagesUpTo(std::shared_ptr<linphone::EventLog> event) { void EventLogList::loadMessagesUpTo(std::shared_ptr<linphone::EventLog> event) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
auto oldestEventLoaded = getAt<EventLogCore>(0); auto oldestEventLoaded = mList.count() > 0 ? getAt<EventLogCore>(mList.count() - 1) : nullptr;
auto linOldest = std::const_pointer_cast<linphone::EventLog>(oldestEventLoaded->getModel()->getEventLog()); auto linOldest = oldestEventLoaded
? std::const_pointer_cast<linphone::EventLog>(oldestEventLoaded->getModel()->getEventLog())
: nullptr;
auto chatModel = mChatCore->getModel(); auto chatModel = mChatCore->getModel();
assert(chatModel); assert(chatModel);
if (!chatModel) return; if (!chatModel) return;
@ -179,45 +190,52 @@ void EventLogList::loadMessagesUpTo(std::shared_ptr<linphone::EventLog> event) {
const auto &linChatRoom = chatModel->getMonitor(); const auto &linChatRoom = chatModel->getMonitor();
for (const auto &it : beforeEvents) { for (const auto &it : beforeEvents) {
auto model = EventLogCore::create(it, linChatRoom); auto model = EventLogCore::create(it, linChatRoom);
events->push_back(model); if (it->getChatMessage() || model->isHandled()) events->push_front(model);
} }
for (const auto &it : linphoneLogs) { for (const auto &it : linphoneLogs) {
auto model = EventLogCore::create(it, linChatRoom); auto model = EventLogCore::create(it, linChatRoom);
events->push_back(model); if (it->getChatMessage() || model->isHandled()) events->push_front(model);
} }
mCoreModelConnection->invokeToCore([this, events, event] { mCoreModelConnection->invokeToCore([this, events, event] {
for (const auto &e : *events) { for (const auto &e : *events) {
connectItem(e); connectItem(e);
add(e);
} }
add(*events);
emit messagesLoadedUpTo(event); emit messagesLoadedUpTo(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.rbegin(), eventList.rend(), [](const QSharedPointer<EventLogCore> item) {
return item->getChatMessageCore() && !item->getChatMessageCore()->isRead(); auto chatmessage = item->getChatMessageCore();
return chatmessage && !chatmessage->isRead();
}); });
return it == eventList.end() ? -1 : std::distance(eventList.begin(), it); return it == eventList.rend() ? -1 : std::distance(it, eventList.rend()) - 1;
} }
void EventLogList::findChatMessageWithFilter(QString filter, void EventLogList::findChatMessageWithFilter(QString filter, int startIndex, bool forward, bool isFirstResearch) {
QSharedPointer<EventLogCore> startEvent,
bool forward,
bool isFirstResearch) {
if (mChatCore) { if (mChatCore) {
if (isFirstResearch) mLastFoundResult.reset(); if (isFirstResearch) mLastFoundResult.reset();
auto chatModel = mChatCore->getModel(); auto chatModel = mChatCore->getModel();
auto startEvent =
startIndex >= 0 && startIndex < mList.count() ? mList[startIndex].objectCast<EventLogCore>() : nullptr;
lInfo() << log().arg("searching event starting from index") << startIndex << "| event :"
<< (startEvent && startEvent->getChatMessageCore() ? startEvent->getChatMessageCore()->getText()
: "null")
<< "| filter :" << filter;
auto startEventModel = startEvent ? startEvent->getModel() : nullptr; auto startEventModel = startEvent ? startEvent->getModel() : nullptr;
mCoreModelConnection->invokeToModel([this, chatModel, startEventModel, filter, forward, isFirstResearch] { mCoreModelConnection->invokeToModel([this, chatModel, startEventModel, filter, forward, isFirstResearch] {
auto linStartEvent = startEventModel ? startEventModel->getEventLog() : nullptr; auto linStartEvent = startEventModel ? startEventModel->getEventLog() : nullptr;
auto eventLog = chatModel->searchMessageByText(filter, linStartEvent, forward); auto eventLog = chatModel->searchMessageByText(filter, linStartEvent, forward);
if (!eventLog) if (!eventLog) {
// event not found, search in the entire history // event not found, search in the entire history
lInfo() << log().arg("not found, search in entire history");
auto eventLog = chatModel->searchMessageByText(filter, nullptr, forward); auto eventLog = chatModel->searchMessageByText(filter, nullptr, forward);
}
int index = -1; int index = -1;
if (eventLog) { if (eventLog) {
lInfo() << log().arg("event with filter found") << eventLog.get();
auto eventList = getSharedList<EventLogCore>(); auto eventList = getSharedList<EventLogCore>();
auto it = std::find_if(eventList.begin(), eventList.end(), auto it = std::find_if(eventList.begin(), eventList.end(),
[eventLog](const QSharedPointer<EventLogCore> item) { [eventLog](const QSharedPointer<EventLogCore> item) {
@ -245,6 +263,7 @@ void EventLogList::findChatMessageWithFilter(QString filter,
loadMessagesUpTo(eventLog); loadMessagesUpTo(eventLog);
} }
} else { } else {
lInfo() << log().arg("event not found at all in history");
mCoreModelConnection->invokeToCore([this, index] { emit messageWithFilterFound(index); }); mCoreModelConnection->invokeToCore([this, index] { emit messageWithFilterFound(index); });
} }
}); });
@ -288,7 +307,7 @@ void EventLogList::setSelf(QSharedPointer<EventLogList> me) {
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, chatModel->getMonitor()); auto model = EventLogCore::create(it, chatModel->getMonitor());
events->push_back(model); if (it->getChatMessage() || model->isHandled()) events->push_front(model);
} }
mCoreModelConnection->invokeToCore([this, events] { mCoreModelConnection->invokeToCore([this, events] {
for (auto &event : *events) { for (auto &event : *events) {

View file

@ -54,13 +54,12 @@ public:
int findFirstUnreadIndex(); int findFirstUnreadIndex();
void markIndexAsRead(int index);
void displayMore(); void displayMore();
void setDisplayItemsStep(int displayItemsStep); void setDisplayItemsStep(int displayItemsStep);
void findChatMessageWithFilter(QString filter, void findChatMessageWithFilter(QString filter, int startIndex, bool forward = true, bool isFirstResearch = true);
QSharedPointer<EventLogCore> startEvent,
bool forward = true,
bool isFirstResearch = true);
void setSelf(QSharedPointer<EventLogList> me); void setSelf(QSharedPointer<EventLogList> me);
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
@ -69,7 +68,7 @@ public:
signals: signals:
void lUpdate(); void lUpdate();
void filterChanged(QString filter); void filterChanged(QString filter);
void eventInserted(int index, EventLogGui *message); void eventInsertedByUser(int index);
void messageWithFilterFound(int index); void messageWithFilterFound(int index);
void listAboutToBeReset(); void listAboutToBeReset();
void chatGuiChanged(); void chatGuiChanged();

View file

@ -26,7 +26,7 @@
DEFINE_ABSTRACT_OBJECT(EventLogProxy) DEFINE_ABSTRACT_OBJECT(EventLogProxy)
EventLogProxy::EventLogProxy(QObject *parent) : LimitProxy(parent) { EventLogProxy::EventLogProxy(QObject *parent) : QSortFilterProxyModel(parent) {
mList = EventLogList::create(); mList = EventLogList::create();
setSourceModel(mList.get()); setSourceModel(mList.get());
} }
@ -35,58 +35,41 @@ EventLogProxy::~EventLogProxy() {
} }
void EventLogProxy::setSourceModel(QAbstractItemModel *model) { void EventLogProxy::setSourceModel(QAbstractItemModel *model) {
auto oldEventLogList = getListModel<EventLogList>(); auto oldEventLogList = dynamic_cast<EventLogList *>(sourceModel());
if (oldEventLogList) { if (oldEventLogList) {
disconnect(oldEventLogList, &EventLogList::listAboutToBeReset, this, nullptr);
disconnect(oldEventLogList, &EventLogList::chatGuiChanged, this, nullptr);
disconnect(oldEventLogList, &EventLogList::displayItemsStepChanged, this, nullptr); disconnect(oldEventLogList, &EventLogList::displayItemsStepChanged, this, nullptr);
disconnect(oldEventLogList, &EventLogList::eventInserted, this, nullptr);
disconnect(oldEventLogList, &EventLogList::messageWithFilterFound, this, nullptr); disconnect(oldEventLogList, &EventLogList::messageWithFilterFound, this, nullptr);
disconnect(oldEventLogList, &EventLogList::eventInsertedByUser, this, nullptr);
} }
auto newEventLogList = dynamic_cast<EventLogList *>(model); auto newEventLogList = dynamic_cast<EventLogList *>(model);
if (newEventLogList) { if (newEventLogList) {
connect(newEventLogList, &EventLogList::listAboutToBeReset, this, &EventLogProxy::listAboutToBeReset);
connect(newEventLogList, &EventLogList::chatGuiChanged, this, &EventLogProxy::chatGuiChanged);
connect(this, &EventLogProxy::displayItemsStepChanged, newEventLogList, connect(this, &EventLogProxy::displayItemsStepChanged, newEventLogList,
[this, newEventLogList] { newEventLogList->setDisplayItemsStep(mDisplayItemsStep); }); [this, newEventLogList] { newEventLogList->setDisplayItemsStep(mDisplayItemsStep); });
connect(newEventLogList, &EventLogList::eventInserted, this,
[this, newEventLogList](int index, EventLogGui *event) {
invalidate();
int proxyIndex = -1;
if (index != -1) {
proxyIndex = dynamic_cast<SortFilterList *>(sourceModel())
->mapFromSource(newEventLogList->index(index, 0))
.row();
}
loadUntil(proxyIndex);
emit eventInserted(proxyIndex, event);
});
connect(newEventLogList, &EventLogList::messageWithFilterFound, this, [this, newEventLogList](int i) { connect(newEventLogList, &EventLogList::messageWithFilterFound, this, [this, newEventLogList](int i) {
connect(this, &EventLogProxy::layoutChanged, newEventLogList, [this, i, newEventLogList] { auto model = dynamic_cast<EventLogList *>(sourceModel());
disconnect(this, &EventLogProxy::layoutChanged, newEventLogList, nullptr); int proxyIndex = mapFromSource(newEventLogList->index(i, 0)).row();
auto model = getListModel<EventLogList>(); if (i != -1) {
int proxyIndex = loadUntil(proxyIndex);
dynamic_cast<SortFilterList *>(sourceModel())->mapFromSource(newEventLogList->index(i, 0)).row(); }
if (i != -1) { emit indexWithFilterFound(proxyIndex);
loadUntil(proxyIndex); });
} connect(newEventLogList, &EventLogList::eventInsertedByUser, this, [this, newEventLogList](int i) {
emit indexWithFilterFound(proxyIndex); int proxyIndex = mapFromSource(newEventLogList->index(i, 0)).row();
}); emit eventInsertedByUser(proxyIndex);
invalidate();
}); });
} }
setSourceModels(new SortFilterList(model, Qt::DescendingOrder)); QSortFilterProxyModel::setSourceModel(model);
sort(0, Qt::DescendingOrder);
} }
ChatGui *EventLogProxy::getChatGui() { ChatGui *EventLogProxy::getChatGui() {
auto model = getListModel<EventLogList>(); auto model = dynamic_cast<EventLogList *>(sourceModel());
if (!mChatGui && model) mChatGui = model->getChat(); if (!mChatGui && model) mChatGui = model->getChat();
return mChatGui; return mChatGui;
} }
void EventLogProxy::setChatGui(ChatGui *chat) { void EventLogProxy::setChatGui(ChatGui *chat) {
getListModel<EventLogList>()->setChatGui(chat); auto model = dynamic_cast<EventLogList *>(sourceModel());
if (model) model->setChatGui(chat);
} }
EventLogGui *EventLogProxy::getEventAtIndex(int i) { EventLogGui *EventLogProxy::getEventAtIndex(int i) {
@ -94,29 +77,86 @@ EventLogGui *EventLogProxy::getEventAtIndex(int i) {
return eventCore == nullptr ? nullptr : new EventLogGui(eventCore); return eventCore == nullptr ? nullptr : new EventLogGui(eventCore);
} }
int EventLogProxy::getCount() const {
return rowCount();
}
int EventLogProxy::getInitialDisplayItems() const {
return mInitialDisplayItems;
}
void EventLogProxy::setInitialDisplayItems(int initialItems) {
if (mInitialDisplayItems != initialItems) {
mInitialDisplayItems = initialItems;
if (getMaxDisplayItems() <= mInitialDisplayItems) setMaxDisplayItems(initialItems);
if (getDisplayItemsStep() <= 0) setDisplayItemsStep(initialItems);
emit initialDisplayItemsChanged();
}
}
int EventLogProxy::getDisplayCount(int listCount, int maxCount) {
return maxCount >= 0 ? qMin(listCount, maxCount) : listCount;
}
int EventLogProxy::getDisplayCount(int listCount) const {
return getDisplayCount(listCount, mMaxDisplayItems);
}
QSharedPointer<EventLogCore> EventLogProxy::getEventCoreAtIndex(int i) { QSharedPointer<EventLogCore> EventLogProxy::getEventCoreAtIndex(int i) {
return getItemAt<SortFilterList, EventLogList, EventLogCore>(i); auto model = dynamic_cast<EventLogList *>(sourceModel());
if (model) {
return model->getAt<EventLogCore>(mapToSource(index(i, 0)).row());
}
return nullptr;
} }
void EventLogProxy::displayMore() { void EventLogProxy::displayMore() {
auto model = getListModel<EventLogList>(); auto model = dynamic_cast<EventLogList *>(sourceModel());
if (model) { if (model) {
model->displayMore(); model->displayMore();
} }
} }
int EventLogProxy::getMaxDisplayItems() const {
return mMaxDisplayItems;
}
void EventLogProxy::setMaxDisplayItems(int maxItems) {
if (mMaxDisplayItems != maxItems) {
auto model = sourceModel();
int modelCount = model ? model->rowCount() : 0;
int oldCount = getDisplayCount(modelCount);
mMaxDisplayItems = maxItems;
if (getInitialDisplayItems() > mMaxDisplayItems) setInitialDisplayItems(maxItems);
if (getDisplayItemsStep() <= 0) setDisplayItemsStep(maxItems);
emit maxDisplayItemsChanged();
if (model && getDisplayCount(modelCount) != oldCount) {
invalidate();
}
}
}
int EventLogProxy::getDisplayItemsStep() const {
return mDisplayItemsStep;
}
void EventLogProxy::setDisplayItemsStep(int step) {
if (step > 0 && mDisplayItemsStep != step) {
mDisplayItemsStep = step;
emit displayItemsStepChanged();
}
}
void EventLogProxy::loadUntil(int index) { void EventLogProxy::loadUntil(int index) {
auto confInfoList = getListModel<EventLogList>();
if (mMaxDisplayItems < index) setMaxDisplayItems(index + mDisplayItemsStep); if (mMaxDisplayItems < index) setMaxDisplayItems(index + mDisplayItemsStep);
} }
int EventLogProxy::findFirstUnreadIndex() { int EventLogProxy::findFirstUnreadIndex() {
auto eventLogList = getListModel<EventLogList>(); auto eventLogList = dynamic_cast<EventLogList *>(sourceModel());
if (eventLogList) { if (eventLogList) {
auto listIndex = eventLogList->findFirstUnreadIndex(); auto listIndex = eventLogList->findFirstUnreadIndex();
if (listIndex != -1) { if (listIndex != -1) {
listIndex = listIndex = mapFromSource(eventLogList->index(listIndex, 0)).row();
dynamic_cast<SortFilterList *>(sourceModel())->mapFromSource(eventLogList->index(listIndex, 0)).row();
if (mMaxDisplayItems <= listIndex) setMaxDisplayItems(listIndex + mDisplayItemsStep); if (mMaxDisplayItems <= listIndex) setMaxDisplayItems(listIndex + mDisplayItemsStep);
return listIndex; return listIndex;
} else { } else {
@ -126,32 +166,43 @@ int EventLogProxy::findFirstUnreadIndex() {
return 0; return 0;
} }
QString EventLogProxy::getFilterText() const {
return mFilterText;
}
void EventLogProxy::setFilterText(const QString &filter) {
if (mFilterText != filter) {
#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
beginFilterChange();
mFilterText = filter;
endFilterChange();
#else
mFilterText = filter;
invalidateFilter();
#endif
emit filterTextChanged();
}
}
QSharedPointer<EventLogCore> EventLogProxy::getAt(int atIndex) const {
auto model = dynamic_cast<EventLogList *>(sourceModel());
if (model) {
return model->getAt<EventLogCore>(mapToSource(index(atIndex, 0)).row());
}
return nullptr;
}
void EventLogProxy::markIndexAsRead(int proxyIndex) { void EventLogProxy::markIndexAsRead(int proxyIndex) {
auto event = getItemAt<SortFilterList, EventLogList, EventLogCore>(proxyIndex); auto event = getAt(proxyIndex);
if (event && event->getChatMessageCore()) event->getChatMessageCore()->lMarkAsRead(); if (event && event->getChatMessageCore()) event->getChatMessageCore()->lMarkAsRead();
} }
void EventLogProxy::findIndexCorrespondingToFilter(int startIndex, bool forward, bool isFirstResearch) { void EventLogProxy::findIndexCorrespondingToFilter(int startIndex, bool forward, bool isFirstResearch) {
auto filter = getFilterText(); auto filter = getFilterText();
if (filter.isEmpty()) return; if (filter.isEmpty()) return;
auto eventLogList = getListModel<EventLogList>(); auto eventLogList = dynamic_cast<EventLogList *>(sourceModel());
if (eventLogList) { if (eventLogList) {
auto startEvent = mLastSearchStart; auto listIndex = mapToSource(index(startIndex, 0)).row();
if (!startEvent) { eventLogList->findChatMessageWithFilter(filter, listIndex, forward, isFirstResearch);
startEvent = getItemAt<SortFilterList, EventLogList, EventLogCore>(startIndex);
}
eventLogList->findChatMessageWithFilter(filter, startEvent, forward, isFirstResearch);
} }
} }
bool EventLogProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
auto l = getItemAtSource<EventLogList, EventLogCore>(sourceRow);
return l != nullptr;
}
bool EventLogProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
auto l = getItemAtSource<EventLogList, EventLogCore>(sourceLeft.row());
auto r = getItemAtSource<EventLogList, EventLogCore>(sourceRight.row());
if (l && r) return l->getTimestamp() < r->getTimestamp();
return true;
}

View file

@ -22,19 +22,26 @@
#define EVENT_LIST_PROXY_H_ #define EVENT_LIST_PROXY_H_
#include "EventLogList.hpp" #include "EventLogList.hpp"
#include "core/proxy/LimitProxy.hpp" // #include "core/proxy/LimitProxy.hpp"
#include "tool/AbstractObject.hpp" #include "tool/AbstractObject.hpp"
#include <QSortFilterProxyModel>
// ============================================================================= // =============================================================================
class ChatGui; class ChatGui;
class EventLogProxy : public LimitProxy, public AbstractObject { class EventLogProxy : public QSortFilterProxyModel, public AbstractObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(int count READ getCount NOTIFY countChanged)
Q_PROPERTY(ChatGui *chatGui READ getChatGui WRITE setChatGui NOTIFY chatGuiChanged) Q_PROPERTY(ChatGui *chatGui READ getChatGui WRITE setChatGui NOTIFY chatGuiChanged)
Q_PROPERTY(int initialDisplayItems READ getInitialDisplayItems WRITE setInitialDisplayItems NOTIFY
initialDisplayItemsChanged)
Q_PROPERTY(int maxDisplayItems READ getMaxDisplayItems WRITE setMaxDisplayItems NOTIFY maxDisplayItemsChanged)
Q_PROPERTY(int displayItemsStep READ getDisplayItemsStep WRITE setDisplayItemsStep NOTIFY displayItemsStepChanged)
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
public: public:
DECLARE_SORTFILTER_CLASS() // DECLARE_SORTFILTER_CLASS()
EventLogProxy(QObject *parent = Q_NULLPTR); EventLogProxy(QObject *parent = Q_NULLPTR);
~EventLogProxy(); ~EventLogProxy();
@ -43,8 +50,27 @@ public:
void setChatGui(ChatGui *chat); void setChatGui(ChatGui *chat);
void setSourceModel(QAbstractItemModel *sourceModel) override; void setSourceModel(QAbstractItemModel *sourceModel) override;
virtual int getCount() const;
static int getDisplayCount(int listCount, int maxCount);
int getDisplayCount(int listCount) const;
int getInitialDisplayItems() const;
void setInitialDisplayItems(int initialItems);
Q_INVOKABLE void displayMore() override; int getMaxDisplayItems() const;
void setMaxDisplayItems(int maxItems);
int getDisplayItemsStep() const;
void setDisplayItemsStep(int step);
QString getFilterText() const;
void setFilterText(const QString &filter);
// bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
// bool lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const override;
QSharedPointer<EventLogCore> getAt(int atIndex) const;
Q_INVOKABLE void displayMore();
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);
@ -53,15 +79,23 @@ public:
Q_INVOKABLE void findIndexCorrespondingToFilter(int startIndex, bool forward = true, bool isFirstResearch = true); Q_INVOKABLE void findIndexCorrespondingToFilter(int startIndex, bool forward = true, bool isFirstResearch = true);
signals: signals:
void eventInserted(int index, EventLogGui *message); void eventInsertedByUser(int index);
void indexWithFilterFound(int index); void indexWithFilterFound(int index);
void listAboutToBeReset();
void chatGuiChanged(); void chatGuiChanged();
void countChanged();
void initialDisplayItemsChanged();
void maxDisplayItemsChanged();
void displayItemsStepChanged();
void filterTextChanged();
protected: protected:
QSharedPointer<EventLogList> mList; QSharedPointer<EventLogList> mList;
QSharedPointer<EventLogCore> mLastSearchStart; QSharedPointer<EventLogCore> mLastSearchStart;
ChatGui *mChatGui = nullptr; ChatGui *mChatGui = nullptr;
int mInitialDisplayItems = -1;
int mMaxDisplayItems = -1;
int mDisplayItemsStep = 5;
QString mFilterText;
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT
}; };

View file

@ -2453,58 +2453,58 @@ Error</extracomment>
<context> <context>
<name>ChatMessagesListView</name> <name>ChatMessagesListView</name>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="123"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="107"/>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="134"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="118"/>
<source>popup_info_find_message_title</source> <source>popup_info_find_message_title</source>
<extracomment>Find message</extracomment> <extracomment>Find message</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="136"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="120"/>
<source>info_popup_no_result_message</source> <source>info_popup_no_result_message</source>
<extracomment>No result found</extracomment> <extracomment>No result found</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="128"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="112"/>
<source>info_popup_first_result_message</source> <source>info_popup_first_result_message</source>
<extracomment>First result reached</extracomment> <extracomment>First result reached</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="126"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="110"/>
<source>info_popup_last_result_message</source> <source>info_popup_last_result_message</source>
<extracomment>Last result reached</extracomment> <extracomment>Last result reached</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="173"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="157"/>
<source>chat_message_list_encrypted_header_title</source> <source>chat_message_list_encrypted_header_title</source>
<extracomment>End to end encrypted chat</extracomment> <extracomment>End to end encrypted chat</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="175"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="159"/>
<source>unencrypted_conversation_warning</source> <source>unencrypted_conversation_warning</source>
<extracomment>This conversation is not encrypted !</extracomment> <extracomment>This conversation is not encrypted !</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="186"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="170"/>
<source>chat_message_list_encrypted_header_message</source> <source>chat_message_list_encrypted_header_message</source>
<extracomment>Messages in this conversation are e2e encrypted. <extracomment>Messages in this conversation are e2e encrypted.
Only your correspondent can decrypt them.</extracomment> Only your correspondent can decrypt them.</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="188"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="172"/>
<source>chat_message_list_not_encrypted_header_message</source> <source>chat_message_list_not_encrypted_header_message</source>
<extracomment>Messages are not end to end encrypted, <extracomment>Messages are not end to end encrypted,
may sure you don&apos;t share any sensitive information !</extracomment> may sure you don&apos;t share any sensitive information !</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="228"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="212"/>
<source>chat_message_is_writing_info</source> <source>chat_message_is_writing_info</source>
<extracomment>%1 is writing</extracomment> <extracomment>%1 is writing</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
@ -3784,58 +3784,58 @@ Error</extracomment>
<context> <context>
<name>EventLogCore</name> <name>EventLogCore</name>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="107"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="113"/>
<source>conference_created_event</source> <source>conference_created_event</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="110"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="119"/>
<source>conference_created_terminated</source> <source>conference_created_terminated</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="114"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="123"/>
<source>conference_participant_added_event</source> <source>conference_participant_added_event</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="118"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="127"/>
<source>conference_participant_removed_event</source> <source>conference_participant_removed_event</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="127"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="136"/>
<location filename="../../core/chat/message/EventLogCore.cpp" line="129"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="138"/>
<source>conference_security_event</source> <source>conference_security_event</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="136"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="145"/>
<source>conference_ephemeral_message_enabled_event</source> <source>conference_ephemeral_message_enabled_event</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="142"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="151"/>
<source>conference_ephemeral_message_lifetime_changed_event</source> <source>conference_ephemeral_message_lifetime_changed_event</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="147"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="156"/>
<source>conference_ephemeral_message_disabled_event</source> <source>conference_ephemeral_message_disabled_event</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="151"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="160"/>
<source>conference_subject_changed_event</source> <source>conference_subject_changed_event</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="159"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="168"/>
<source>conference_participant_unset_admin_event</source> <source>conference_participant_unset_admin_event</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="155"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="164"/>
<source>conference_participant_set_admin_event</source> <source>conference_participant_set_admin_event</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -5828,42 +5828,42 @@ Pour les activer dans un projet commercial, merci de nous contacter.</source>
<context> <context>
<name>SelectedChatView</name> <name>SelectedChatView</name>
<message> <message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="50"/> <location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="48"/>
<source>chat_view_group_call_toast_message</source> <source>chat_view_group_call_toast_message</source>
<translation>Start a group call ?</translation> <translation>Start a group call ?</translation>
</message> </message>
<message> <message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="133"/> <location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="131"/>
<source>unencrypted_conversation_warning</source> <source>unencrypted_conversation_warning</source>
<extracomment>This conversation is not encrypted !</extracomment> <extracomment>This conversation is not encrypted !</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="419"/> <location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="417"/>
<source>reply_to_label</source> <source>reply_to_label</source>
<extracomment>Reply to %1</extracomment> <extracomment>Reply to %1</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="619"/> <location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="617"/>
<source>shared_medias_title</source> <source>shared_medias_title</source>
<extracomment>Shared medias</extracomment> <extracomment>Shared medias</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="621"/> <location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="619"/>
<source>shared_documents_title</source> <source>shared_documents_title</source>
<extracomment>Shared documents</extracomment> <extracomment>Shared documents</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="650"/> <location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="648"/>
<source>forward_to_title</source> <source>forward_to_title</source>
<extracomment>Forward to</extracomment> <extracomment>Forward to</extracomment>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="684"/> <location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="682"/>
<source>conversations_title</source> <source>conversations_title</source>
<extracomment>Conversations</extracomment> <extracomment>Conversations</extracomment>
<translation>Konversationen</translation> <translation>Konversationen</translation>

View file

@ -2425,44 +2425,44 @@ Error</extracomment>
<context> <context>
<name>ChatMessagesListView</name> <name>ChatMessagesListView</name>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="123"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="107"/>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="134"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="118"/>
<source>popup_info_find_message_title</source> <source>popup_info_find_message_title</source>
<extracomment>Find message</extracomment> <extracomment>Find message</extracomment>
<translation>Find message</translation> <translation>Find message</translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="136"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="120"/>
<source>info_popup_no_result_message</source> <source>info_popup_no_result_message</source>
<extracomment>No result found</extracomment> <extracomment>No result found</extracomment>
<translation>No result found</translation> <translation>No result found</translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="128"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="112"/>
<source>info_popup_first_result_message</source> <source>info_popup_first_result_message</source>
<extracomment>First result reached</extracomment> <extracomment>First result reached</extracomment>
<translation>First result reached</translation> <translation>First result reached</translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="126"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="110"/>
<source>info_popup_last_result_message</source> <source>info_popup_last_result_message</source>
<extracomment>Last result reached</extracomment> <extracomment>Last result reached</extracomment>
<translation>Last result reached</translation> <translation>Last result reached</translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="173"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="157"/>
<source>chat_message_list_encrypted_header_title</source> <source>chat_message_list_encrypted_header_title</source>
<extracomment>End to end encrypted chat</extracomment> <extracomment>End to end encrypted chat</extracomment>
<translation>End to end encrypted chat</translation> <translation>End to end encrypted chat</translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="175"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="159"/>
<source>unencrypted_conversation_warning</source> <source>unencrypted_conversation_warning</source>
<extracomment>This conversation is not encrypted !</extracomment> <extracomment>This conversation is not encrypted !</extracomment>
<translation>This conversation is not encrypted !</translation> <translation>This conversation is not encrypted !</translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="186"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="170"/>
<source>chat_message_list_encrypted_header_message</source> <source>chat_message_list_encrypted_header_message</source>
<extracomment>Messages in this conversation are e2e encrypted. <extracomment>Messages in this conversation are e2e encrypted.
Only your correspondent can decrypt them.</extracomment> Only your correspondent can decrypt them.</extracomment>
@ -2470,7 +2470,7 @@ Error</extracomment>
Only your correspondent can decrypt them.</translation> Only your correspondent can decrypt them.</translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="188"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="172"/>
<source>chat_message_list_not_encrypted_header_message</source> <source>chat_message_list_not_encrypted_header_message</source>
<extracomment>Messages are not end to end encrypted, <extracomment>Messages are not end to end encrypted,
may sure you don&apos;t share any sensitive information !</extracomment> may sure you don&apos;t share any sensitive information !</extracomment>
@ -2478,7 +2478,7 @@ Only your correspondent can decrypt them.</translation>
may sure you don&apos;t share any sensitive information !</translation> may sure you don&apos;t share any sensitive information !</translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="228"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="212"/>
<source>chat_message_is_writing_info</source> <source>chat_message_is_writing_info</source>
<extracomment>%1 is writing</extracomment> <extracomment>%1 is writing</extracomment>
<translation>%1 is writing</translation> <translation>%1 is writing</translation>
@ -3703,59 +3703,59 @@ Only your correspondent can decrypt them.</translation>
<context> <context>
<name>EventLogCore</name> <name>EventLogCore</name>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="107"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="113"/>
<source>conference_created_event</source> <source>conference_created_event</source>
<translation>You have joined the group</translation> <translation>You have joined the group</translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="110"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="119"/>
<source>conference_created_terminated</source> <source>conference_created_terminated</source>
<translation>You have left the group</translation> <translation>You have left the group</translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="114"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="123"/>
<source>conference_participant_added_event</source> <source>conference_participant_added_event</source>
<translation>%1 has joined</translation> <translation>%1 has joined</translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="118"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="127"/>
<source>conference_participant_removed_event</source> <source>conference_participant_removed_event</source>
<translation>%1 is no longer in the conversation</translation> <translation>%1 is no longer in the conversation</translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="155"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="164"/>
<source>conference_participant_set_admin_event</source> <source>conference_participant_set_admin_event</source>
<translation>%1 is now an admin</translation> <translation>%1 is now an admin</translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="159"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="168"/>
<source>conference_participant_unset_admin_event</source> <source>conference_participant_unset_admin_event</source>
<translation>%1 is no longer an admin</translation> <translation>%1 is no longer an admin</translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="127"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="136"/>
<location filename="../../core/chat/message/EventLogCore.cpp" line="129"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="138"/>
<source>conference_security_event</source> <source>conference_security_event</source>
<translation>Security level degraded by %1</translation> <translation>Security level degraded by %1</translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="136"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="145"/>
<source>conference_ephemeral_message_enabled_event</source> <source>conference_ephemeral_message_enabled_event</source>
<translation>Ephemeral messages enabled <translation>Ephemeral messages enabled
Expiration : %1</translation> Expiration : %1</translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="147"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="156"/>
<source>conference_ephemeral_message_disabled_event</source> <source>conference_ephemeral_message_disabled_event</source>
<translation>Ephemeral messages disabled</translation> <translation>Ephemeral messages disabled</translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="151"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="160"/>
<source>conference_subject_changed_event</source> <source>conference_subject_changed_event</source>
<translation>New subject: %1</translation> <translation>New subject: %1</translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="142"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="151"/>
<source>conference_ephemeral_message_lifetime_changed_event</source> <source>conference_ephemeral_message_lifetime_changed_event</source>
<translation>Ephemeral messages updated <translation>Ephemeral messages updated
Expiration : %1</translation> Expiration : %1</translation>
@ -5723,42 +5723,42 @@ To enable them in a commercial project, please contact us.</translation>
<context> <context>
<name>SelectedChatView</name> <name>SelectedChatView</name>
<message> <message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="50"/> <location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="48"/>
<source>chat_view_group_call_toast_message</source> <source>chat_view_group_call_toast_message</source>
<translation>Start a group call ?</translation> <translation>Start a group call ?</translation>
</message> </message>
<message> <message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="133"/> <location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="131"/>
<source>unencrypted_conversation_warning</source> <source>unencrypted_conversation_warning</source>
<extracomment>This conversation is not encrypted !</extracomment> <extracomment>This conversation is not encrypted !</extracomment>
<translation>This conversation is not encrypted !</translation> <translation>This conversation is not encrypted !</translation>
</message> </message>
<message> <message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="419"/> <location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="417"/>
<source>reply_to_label</source> <source>reply_to_label</source>
<extracomment>Reply to %1</extracomment> <extracomment>Reply to %1</extracomment>
<translation>Reply to %1</translation> <translation>Reply to %1</translation>
</message> </message>
<message> <message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="619"/> <location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="617"/>
<source>shared_medias_title</source> <source>shared_medias_title</source>
<extracomment>Shared medias</extracomment> <extracomment>Shared medias</extracomment>
<translation>Shared medias</translation> <translation>Shared medias</translation>
</message> </message>
<message> <message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="621"/> <location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="619"/>
<source>shared_documents_title</source> <source>shared_documents_title</source>
<extracomment>Shared documents</extracomment> <extracomment>Shared documents</extracomment>
<translation>Shared documents</translation> <translation>Shared documents</translation>
</message> </message>
<message> <message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="650"/> <location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="648"/>
<source>forward_to_title</source> <source>forward_to_title</source>
<extracomment>Forward to</extracomment> <extracomment>Forward to</extracomment>
<translation>Froward to</translation> <translation>Froward to</translation>
</message> </message>
<message> <message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="684"/> <location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="682"/>
<source>conversations_title</source> <source>conversations_title</source>
<extracomment>Conversations</extracomment> <extracomment>Conversations</extracomment>
<translation>Conversations</translation> <translation>Conversations</translation>

View file

@ -2425,44 +2425,44 @@ Error</extracomment>
<context> <context>
<name>ChatMessagesListView</name> <name>ChatMessagesListView</name>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="123"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="107"/>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="134"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="118"/>
<source>popup_info_find_message_title</source> <source>popup_info_find_message_title</source>
<extracomment>Find message</extracomment> <extracomment>Find message</extracomment>
<translation>Trouver un message</translation> <translation>Trouver un message</translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="136"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="120"/>
<source>info_popup_no_result_message</source> <source>info_popup_no_result_message</source>
<extracomment>No result found</extracomment> <extracomment>No result found</extracomment>
<translation>Aucun résultat trouvé</translation> <translation>Aucun résultat trouvé</translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="128"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="112"/>
<source>info_popup_first_result_message</source> <source>info_popup_first_result_message</source>
<extracomment>First result reached</extracomment> <extracomment>First result reached</extracomment>
<translation>Premier résultat atteint</translation> <translation>Premier résultat atteint</translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="126"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="110"/>
<source>info_popup_last_result_message</source> <source>info_popup_last_result_message</source>
<extracomment>Last result reached</extracomment> <extracomment>Last result reached</extracomment>
<translation>Dernier résultat atteint</translation> <translation>Dernier résultat atteint</translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="173"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="157"/>
<source>chat_message_list_encrypted_header_title</source> <source>chat_message_list_encrypted_header_title</source>
<extracomment>End to end encrypted chat</extracomment> <extracomment>End to end encrypted chat</extracomment>
<translation>Conversation chiffrée de bout en bout</translation> <translation>Conversation chiffrée de bout en bout</translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="175"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="159"/>
<source>unencrypted_conversation_warning</source> <source>unencrypted_conversation_warning</source>
<extracomment>This conversation is not encrypted !</extracomment> <extracomment>This conversation is not encrypted !</extracomment>
<translation>Cette conversation n&apos;est pas chiffrée !</translation> <translation>Cette conversation n&apos;est pas chiffrée !</translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="186"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="170"/>
<source>chat_message_list_encrypted_header_message</source> <source>chat_message_list_encrypted_header_message</source>
<extracomment>Messages in this conversation are e2e encrypted. <extracomment>Messages in this conversation are e2e encrypted.
Only your correspondent can decrypt them.</extracomment> Only your correspondent can decrypt them.</extracomment>
@ -2470,7 +2470,7 @@ Error</extracomment>
en bout. Seul votre correspondant peut les déchiffrer.</translation> en bout. Seul votre correspondant peut les déchiffrer.</translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="188"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="172"/>
<source>chat_message_list_not_encrypted_header_message</source> <source>chat_message_list_not_encrypted_header_message</source>
<extracomment>Messages are not end to end encrypted, <extracomment>Messages are not end to end encrypted,
may sure you don&apos;t share any sensitive information !</extracomment> may sure you don&apos;t share any sensitive information !</extracomment>
@ -2478,7 +2478,7 @@ en bout. Seul votre correspondant peut les déchiffrer.</translation>
assurez-vous de ne pas partager dinformations sensibles !</translation> assurez-vous de ne pas partager dinformations sensibles !</translation>
</message> </message>
<message> <message>
<location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="228"/> <location filename="../../view/Control/Display/Chat/ChatMessagesListView.qml" line="212"/>
<source>chat_message_is_writing_info</source> <source>chat_message_is_writing_info</source>
<extracomment>%1 is writing</extracomment> <extracomment>%1 is writing</extracomment>
<translation>%1 est en train d&apos;écrire</translation> <translation>%1 est en train d&apos;écrire</translation>
@ -3703,60 +3703,60 @@ en bout. Seul votre correspondant peut les déchiffrer.</translation>
<context> <context>
<name>EventLogCore</name> <name>EventLogCore</name>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="107"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="113"/>
<source>conference_created_event</source> <source>conference_created_event</source>
<translation>Vous avez rejoint le groupe</translation> <translation>Vous avez rejoint le groupe</translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="110"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="119"/>
<source>conference_created_terminated</source> <source>conference_created_terminated</source>
<translation>Vous avez quitté le groupe</translation> <translation>Vous avez quitté le groupe</translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="114"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="123"/>
<source>conference_participant_added_event</source> <source>conference_participant_added_event</source>
<translation>%1 a rejoint le groupe</translation> <translation>%1 a rejoint le groupe</translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="118"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="127"/>
<source>conference_participant_removed_event</source> <source>conference_participant_removed_event</source>
<translation>%1 ne fait plus partie du groupe</translation> <translation>%1 ne fait plus partie du groupe</translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="127"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="136"/>
<location filename="../../core/chat/message/EventLogCore.cpp" line="129"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="138"/>
<source>conference_security_event</source> <source>conference_security_event</source>
<translation>Niveau de sécurité dégradé par %1</translation> <translation>Niveau de sécurité dégradé par %1</translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="136"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="145"/>
<source>conference_ephemeral_message_enabled_event</source> <source>conference_ephemeral_message_enabled_event</source>
<translation>Messages éphémères activés <translation>Messages éphémères activés
Expiration : %1</translation> Expiration : %1</translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="142"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="151"/>
<source>conference_ephemeral_message_lifetime_changed_event</source> <source>conference_ephemeral_message_lifetime_changed_event</source>
<translation>Messages éphémères mis à jour <translation>Messages éphémères mis à jour
Expiration : %1</translation> Expiration : %1</translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="147"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="156"/>
<source>conference_ephemeral_message_disabled_event</source> <source>conference_ephemeral_message_disabled_event</source>
<translation>Messages éphémères désactivés</translation> <translation>Messages éphémères désactivés</translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="151"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="160"/>
<source>conference_subject_changed_event</source> <source>conference_subject_changed_event</source>
<translation>Nouveau sujet : %1</translation> <translation>Nouveau sujet : %1</translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="159"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="168"/>
<source>conference_participant_unset_admin_event</source> <source>conference_participant_unset_admin_event</source>
<translation>%1 n&apos;est plus admin</translation> <translation>%1 n&apos;est plus admin</translation>
</message> </message>
<message> <message>
<location filename="../../core/chat/message/EventLogCore.cpp" line="155"/> <location filename="../../core/chat/message/EventLogCore.cpp" line="164"/>
<source>conference_participant_set_admin_event</source> <source>conference_participant_set_admin_event</source>
<translation>%1 est maintenant admin</translation> <translation>%1 est maintenant admin</translation>
</message> </message>
@ -5723,42 +5723,42 @@ Pour les activer dans un projet commercial, merci de nous contacter.</translatio
<context> <context>
<name>SelectedChatView</name> <name>SelectedChatView</name>
<message> <message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="50"/> <location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="48"/>
<source>chat_view_group_call_toast_message</source> <source>chat_view_group_call_toast_message</source>
<translation>Démarrer un appel de groupe ?</translation> <translation>Démarrer un appel de groupe ?</translation>
</message> </message>
<message> <message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="133"/> <location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="131"/>
<source>unencrypted_conversation_warning</source> <source>unencrypted_conversation_warning</source>
<extracomment>This conversation is not encrypted !</extracomment> <extracomment>This conversation is not encrypted !</extracomment>
<translation>Cette conversation n&apos;est pas chiffrée !</translation> <translation>Cette conversation n&apos;est pas chiffrée !</translation>
</message> </message>
<message> <message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="419"/> <location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="417"/>
<source>reply_to_label</source> <source>reply_to_label</source>
<extracomment>Reply to %1</extracomment> <extracomment>Reply to %1</extracomment>
<translation>Réponse à %1</translation> <translation>Réponse à %1</translation>
</message> </message>
<message> <message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="619"/> <location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="617"/>
<source>shared_medias_title</source> <source>shared_medias_title</source>
<extracomment>Shared medias</extracomment> <extracomment>Shared medias</extracomment>
<translation>Médias partagés</translation> <translation>Médias partagés</translation>
</message> </message>
<message> <message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="621"/> <location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="619"/>
<source>shared_documents_title</source> <source>shared_documents_title</source>
<extracomment>Shared documents</extracomment> <extracomment>Shared documents</extracomment>
<translation>Documents partagés</translation> <translation>Documents partagés</translation>
</message> </message>
<message> <message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="650"/> <location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="648"/>
<source>forward_to_title</source> <source>forward_to_title</source>
<extracomment>Forward to</extracomment> <extracomment>Forward to</extracomment>
<translation>Transférer à</translation> <translation>Transférer à</translation>
</message> </message>
<message> <message>
<location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="684"/> <location filename="../../view/Page/Form/Chat/SelectedChatView.qml" line="682"/>
<source>conversations_title</source> <source>conversations_title</source>
<extracomment>Conversations</extracomment> <extracomment>Conversations</extracomment>
<translation>Conversations</translation> <translation>Conversations</translation>

View file

@ -18,6 +18,7 @@ ListView {
property real busyIndicatorSize: Utils.getSizeWithScreenRatio(60) property real busyIndicatorSize: Utils.getSizeWithScreenRatio(60)
property bool loading: false property bool loading: false
property bool isEncrypted: chat && chat.core.isEncrypted property bool isEncrypted: chat && chat.core.isEncrypted
highlightFollowsCurrentItem: false
verticalLayoutDirection: ListView.BottomToTop verticalLayoutDirection: ListView.BottomToTop
signal showReactionsForMessageRequested(ChatMessageGui chatMessage) signal showReactionsForMessageRequested(ChatMessageGui chatMessage)
@ -40,24 +41,16 @@ ListView {
property bool searchForward: true property bool searchForward: true
onFindIndexWithFilter: (forward) => { onFindIndexWithFilter: (forward) => {
searchForward = forward searchForward = forward
eventLogProxy.findIndexCorrespondingToFilter(currentIndex, forward, false) eventLogProxy.findIndexCorrespondingToFilter(currentIndex, searchForward, false)
}
Component.onCompleted: {
Qt.callLater(function() {
var index = eventLogProxy.findFirstUnreadIndex()
positionViewAtIndex(index, ListView.Beginning)
eventLogProxy.markIndexAsRead(index)
})
} }
Button { Button {
visible: !mainItem.lastItemVisible visible: !mainItem.lastItemVisible
icon.source: AppIcons.downArrow icon.source: AppIcons.downArrow
leftPadding: Utils.getSizeWithScreenRatio(16) leftPadding: Utils.getSizeWithScreenRatio(20)
rightPadding: Utils.getSizeWithScreenRatio(16) rightPadding: Utils.getSizeWithScreenRatio(20)
topPadding: Utils.getSizeWithScreenRatio(16) topPadding: Utils.getSizeWithScreenRatio(20)
bottomPadding: Utils.getSizeWithScreenRatio(16) bottomPadding: Utils.getSizeWithScreenRatio(20)
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
style: ButtonStyle.main style: ButtonStyle.main
anchors.right: parent.right anchors.right: parent.right
@ -65,20 +58,24 @@ ListView {
anchors.rightMargin: Utils.getSizeWithScreenRatio(18) anchors.rightMargin: Utils.getSizeWithScreenRatio(18)
onClicked: { onClicked: {
var index = eventLogProxy.findFirstUnreadIndex() var index = eventLogProxy.findFirstUnreadIndex()
mainItem.positionViewAtIndex(index, ListView.Beginning) mainItem.positionViewAtIndex(index, ListView.Contain)
eventLogProxy.markIndexAsRead(index) eventLogProxy.markIndexAsRead(index)
} }
UnreadNotification {
anchors.top: parent.top
anchors.right: parent.right
anchors.topMargin: Utils.getSizeWithScreenRatio(-5)
anchors.rightMargin: Utils.getSizeWithScreenRatio(-5)
unread: mainItem.chat?.core.unreadMessagesCount || 0
}
} }
onAtYEndChanged: if (atYEnd && chat) {
chat.core.lMarkAsRead()
}
// Workaround : check if there is already items in the list
// so this function is only called when the user actually scroll
// the view till the begining
onAtYBeginningChanged: if (atYBeginning && count !== 0) { onAtYBeginningChanged: if (atYBeginning && count !== 0) {
eventLogProxy.displayMore() eventLogProxy.displayMore()
} }
onAtYEndChanged: if (atYEnd && chat) {
chat.core.lMarkAsRead()
}
model: EventLogProxy { model: EventLogProxy {
id: eventLogProxy id: eventLogProxy
@ -86,23 +83,18 @@ ListView {
filterText: mainItem.filterText filterText: mainItem.filterText
initialDisplayItems: 20 initialDisplayItems: 20
displayItemsStep: 20 displayItemsStep: 20
onEventInserted: (index, gui) => {
if (!mainItem.visible) return
if(mainItem.lastItemVisible) {
mainItem.positionViewAtIndex(index, ListView.Beginning)
markIndexAsRead(index)
}
}
onModelAboutToBeReset: { onModelAboutToBeReset: {
loading = true loading = true
} }
onModelReset: { onModelReset: {
loading = false loading = false
var index = eventLogProxy.findFirstUnreadIndex() var index = eventLogProxy.findFirstUnreadIndex()
positionViewAtIndex(index, ListView.Beginning) mainItem.positionViewAtIndex(index, ListView.Contain)
eventLogProxy.markIndexAsRead(index) eventLogProxy.markIndexAsRead(index)
} }
onChatGuiChanged: forceLayout() onEventInsertedByUser: (index) => {
mainItem.positionViewAtIndex(index, ListView.Beginning)
}
onIndexWithFilterFound: (index) => { onIndexWithFilterFound: (index) => {
if (index !== -1) { if (index !== -1) {
currentIndex = index currentIndex = index
@ -249,9 +241,10 @@ ListView {
} }
} }
Component.onCompleted: { Component.onCompleted: {
if (index === 0) mainItem.lastItemVisible = isFullyVisible if (index === 0) {
mainItem.lastItemVisible = isFullyVisible
}
} }
// onYChanged: if (index === 0) mainItem.lastItemVisible = isFullyVisible
chat: mainItem.chat chat: mainItem.chat
searchedTextPart: mainItem.filterText searchedTextPart: mainItem.filterText
maxWidth: Math.round(mainItem.width * (3/4)) maxWidth: Math.round(mainItem.width * (3/4))

View file

@ -27,13 +27,11 @@ FocusScope {
signal groupCall() signal groupCall()
onActiveFocusChanged: if(activeFocus) { onActiveFocusChanged: if(activeFocus) {
console.log("selected has active focus, mark as read") if (chatMessagesListView.lastItemVisible) chat.core.lMarkAsRead()
chat.core.lMarkAsRead()
} }
MouseArea{ MouseArea{
anchors.fill: parent anchors.fill: parent
onPressed: { onPressed: {
console.log("selected chat view pressed")
forceActiveFocus() forceActiveFocus()
} }
} }