Unread chat message event.

Shortcut to go at the end of chat.
Avoid MarkAsRead when not at end of chat.
Fix composers.
This commit is contained in:
Julien Wadel 2022-01-07 11:52:51 +01:00
parent 922d155146
commit 821d1e17da
28 changed files with 397 additions and 42 deletions

View file

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="80"
height="80"
viewBox="0 0 80 80"
version="1.1"
id="svg11"
sodipodi:docname="bottom_move_custom.svg"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata
id="metadata15">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>drop_down_list</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1043"
id="namedview13"
showgrid="false"
inkscape:zoom="5.9599"
inkscape:cx="4.2785953"
inkscape:cy="30.201849"
inkscape:window-x="1920"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg11"
inkscape:pagecheckerboard="0" />
<!-- Generator: Sketch 42 (36781) - http://www.bohemiancoding.com/sketch -->
<title
id="title2">drop_down_list</title>
<desc
id="desc4">Created with Sketch.</desc>
<defs
id="defs6" />
<g
id="Symbols"
style="fill:none;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round"
transform="matrix(3.3369868,0,0,2.857815,20,21)">
<g
id="drop_down_list"
style="stroke:#000000;stroke-width:2">
<path
d="m 3.5,8.5 5,-5 M 3.5041964,-1.5 8.5,3.5"
id="status_username_disconnected"
transform="rotate(90,6,3.5)"
inkscape:connector-curvature="0" />
</g>
</g>
<g
id="Symbols-3"
style="fill:none;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round"
transform="matrix(3.3369868,0,0,2.857815,20,30)">
<g
id="drop_down_list-6"
style="stroke:#000000;stroke-width:2">
<path
d="m 1,3.0995062 5,5 M 11,3.1037026 6,8.0995062"
id="status_username_disconnected-7"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -1563,6 +1563,14 @@ Klik her: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<extracomment>&apos;Ephemeral messages have been updated: %1&apos; : Little message to show on the event when ephemeral has been updated. %1 is a date time</extracomment>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<source>unreadMessageNotice</source>
<extracomment>&apos;%1 unread messages&apos; : Little message to show on an event where unread messages begin.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
</context>
<context>
<name>Notifier</name>

View file

@ -1563,6 +1563,14 @@ Klicken Sie hier: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<extracomment>&apos;Ephemeral messages have been updated: %1&apos; : Little message to show on the event when ephemeral has been updated. %1 is a date time</extracomment>
<translation>Kurzlebige Nachrichten wurden aktualisiert: %1</translation>
</message>
<message numerus="yes">
<source>unreadMessageNotice</source>
<extracomment>&apos;%1 unread messages&apos; : Little message to show on an event where unread messages begin.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
</context>
<context>
<name>Notifier</name>

View file

@ -1563,6 +1563,14 @@ Click here: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<extracomment>&apos;Ephemeral messages have been updated: %1&apos; : Little message to show on the event when ephemeral has been updated. %1 is a date time</extracomment>
<translation>Ephemeral messages have been updated: %1</translation>
</message>
<message numerus="yes">
<source>unreadMessageNotice</source>
<extracomment>&apos;%1 unread messages&apos; : Little message to show on an event where unread messages begin.</extracomment>
<translation>
<numerusform>%1 unread message</numerusform>
<numerusform>%1 unread messages</numerusform>
</translation>
</message>
</context>
<context>
<name>Notifier</name>

View file

@ -1563,6 +1563,14 @@ Haga clic aquí: &lt;a href=&quot;%1&quot;&gt;%1 &lt;/a&gt;
<extracomment>&apos;Ephemeral messages have been updated: %1&apos; : Little message to show on the event when ephemeral has been updated. %1 is a date time</extracomment>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<source>unreadMessageNotice</source>
<extracomment>&apos;%1 unread messages&apos; : Little message to show on an event where unread messages begin.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
</context>
<context>
<name>Notifier</name>

View file

@ -1563,6 +1563,14 @@ Cliquez ici : &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<extracomment>&apos;Ephemeral messages have been updated: %1&apos; : Little message to show on the event when ephemeral has been updated. %1 is a date time</extracomment>
<translation>Délai dexpiration des messages : %1</translation>
</message>
<message numerus="yes">
<source>unreadMessageNotice</source>
<extracomment>&apos;%1 unread messages&apos; : Little message to show on an event where unread messages begin.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
</context>
<context>
<name>Notifier</name>

View file

@ -1553,6 +1553,13 @@ Kattintson ide: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<extracomment>&apos;Ephemeral messages have been updated: %1&apos; : Little message to show on the event when ephemeral has been updated. %1 is a date time</extracomment>
<translation>Mulandó üzenetek frissítve: %1</translation>
</message>
<message numerus="yes">
<source>unreadMessageNotice</source>
<extracomment>&apos;%1 unread messages&apos; : Little message to show on an event where unread messages begin.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
</translation>
</message>
</context>
<context>
<name>Notifier</name>

View file

@ -1563,6 +1563,14 @@ Clicca: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<extracomment>&apos;Ephemeral messages have been updated: %1&apos; : Little message to show on the event when ephemeral has been updated. %1 is a date time</extracomment>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<source>unreadMessageNotice</source>
<extracomment>&apos;%1 unread messages&apos; : Little message to show on an event where unread messages begin.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
</context>
<context>
<name>Notifier</name>

View file

@ -1553,6 +1553,13 @@
<extracomment>&apos;Ephemeral messages have been updated: %1&apos; : Little message to show on the event when ephemeral has been updated. %1 is a date time</extracomment>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<source>unreadMessageNotice</source>
<extracomment>&apos;%1 unread messages&apos; : Little message to show on an event where unread messages begin.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
</translation>
</message>
</context>
<context>
<name>Notifier</name>

View file

@ -1573,6 +1573,15 @@ Spustelėkite čia: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<extracomment>&apos;Ephemeral messages have been updated: %1&apos; : Little message to show on the event when ephemeral has been updated. %1 is a date time</extracomment>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<source>unreadMessageNotice</source>
<extracomment>&apos;%1 unread messages&apos; : Little message to show on an event where unread messages begin.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
</context>
<context>
<name>Notifier</name>

View file

@ -1563,6 +1563,14 @@ Clique aqui: &lt;a href=&quot;%1&quot;&gt;%1 &lt;/a&gt;
<extracomment>&apos;Ephemeral messages have been updated: %1&apos; : Little message to show on the event when ephemeral has been updated. %1 is a date time</extracomment>
<translation>Mensagens efêmeras foram atualizadas: %1</translation>
</message>
<message numerus="yes">
<source>unreadMessageNotice</source>
<extracomment>&apos;%1 unread messages&apos; : Little message to show on an event where unread messages begin.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
</context>
<context>
<name>Notifier</name>

View file

@ -1573,6 +1573,15 @@
<extracomment>&apos;Ephemeral messages have been updated: %1&apos; : Little message to show on the event when ephemeral has been updated. %1 is a date time</extracomment>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<source>unreadMessageNotice</source>
<extracomment>&apos;%1 unread messages&apos; : Little message to show on an event where unread messages begin.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
</context>
<context>
<name>Notifier</name>

View file

@ -1563,6 +1563,14 @@ Klicka här: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<extracomment>&apos;Ephemeral messages have been updated: %1&apos; : Little message to show on the event when ephemeral has been updated. %1 is a date time</extracomment>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<source>unreadMessageNotice</source>
<extracomment>&apos;%1 unread messages&apos; : Little message to show on an event where unread messages begin.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
</context>
<context>
<name>Notifier</name>

View file

@ -1553,6 +1553,13 @@ Buraya tıklayın: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
<extracomment>&apos;Ephemeral messages have been updated: %1&apos; : Little message to show on the event when ephemeral has been updated. %1 is a date time</extracomment>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<source>unreadMessageNotice</source>
<extracomment>&apos;%1 unread messages&apos; : Little message to show on an event where unread messages begin.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
</translation>
</message>
</context>
<context>
<name>Notifier</name>

View file

@ -1573,6 +1573,15 @@
<extracomment>&apos;Ephemeral messages have been updated: %1&apos; : Little message to show on the event when ephemeral has been updated. %1 is a date time</extracomment>
<translation type="unfinished"></translation>
</message>
<message numerus="yes">
<source>unreadMessageNotice</source>
<extracomment>&apos;%1 unread messages&apos; : Little message to show on an event where unread messages begin.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
<numerusform></numerusform>
<numerusform></numerusform>
</translation>
</message>
</context>
<context>
<name>Notifier</name>

View file

@ -1553,6 +1553,13 @@
<extracomment>&apos;Ephemeral messages have been updated: %1&apos; : Little message to show on the event when ephemeral has been updated. %1 is a date time</extracomment>
<translation> %1</translation>
</message>
<message numerus="yes">
<source>unreadMessageNotice</source>
<extracomment>&apos;%1 unread messages&apos; : Little message to show on an event where unread messages begin.</extracomment>
<translation type="unfinished">
<numerusform></numerusform>
</translation>
</message>
</context>
<context>
<name>Notifier</name>

View file

@ -98,6 +98,7 @@
<file>assets/images/micro_on_custom.svg</file>
<file>assets/images/missed_incoming_call_custom.svg</file>
<file>assets/images/missed_outgoing_call_custom.svg</file>
<file>assets/images/move_to_bottom_custom.svg</file>
<file>assets/images/new_call_custom.svg</file>
<file>assets/images/new_chat_group_custom.svg</file>
<file>assets/images/new_conference_custom.svg</file>

View file

@ -34,6 +34,14 @@ ChatNoticeModel::ChatNoticeModel ( std::shared_ptr<linphone::EventLog> eventLog,
mTimestamp = QDateTime::fromMSecsSinceEpoch(eventLog->getCreationTime() * 1000);
}
ChatNoticeModel::ChatNoticeModel ( NoticeType noticeType, const QDateTime& timestamp, const QString& txt, QObject * parent) : ChatEvent(ChatRoomModel::EntryType::NoticeEntry, parent) {
App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE
mEventLogType = LinphoneEnums::EventLogType::EventLogTypeNone;
setStatus(noticeType);
setName(txt);
mTimestamp = timestamp;
}
ChatNoticeModel::~ChatNoticeModel(){
}
@ -46,6 +54,15 @@ std::shared_ptr<ChatNoticeModel> ChatNoticeModel::create(std::shared_ptr<linphon
return nullptr;
}
std::shared_ptr<ChatNoticeModel> ChatNoticeModel::create(NoticeType noticeType, const QDateTime& timestamp, const QString& txt, QObject * parent){
auto model = std::make_shared<ChatNoticeModel>(noticeType, timestamp, txt, parent);
if(model ){
model->mSelf = model;
return model;
}else
return nullptr;
}
std::shared_ptr<linphone::EventLog> ChatNoticeModel::getEventLog(){
return mEventLog;
}
@ -53,6 +70,8 @@ std::shared_ptr<linphone::EventLog> ChatNoticeModel::getEventLog(){
//---------------------------------------------------------------------------------------------
bool ChatNoticeModel::update(){
bool handledEvent = true;
if(!mEventLog)
return false;
auto participantAddress = mEventLog->getParticipantAddress();
switch(mEventLog->getType()){
@ -158,5 +177,6 @@ void ChatNoticeModel::setEventLogType(const LinphoneEnums::EventLogType& data){
}
void ChatNoticeModel::deleteEvent(){
mEventLog->deleteFromDatabase();
if(mEventLog)
mEventLog->deleteFromDatabase();
}

View file

@ -32,16 +32,19 @@ class ChatNoticeModel : public ChatEvent {
public:
enum NoticeType {
NoticeMessage,
NoticeError
NoticeMessage, // This is a Linphone message
NoticeError, // This is a Linphone error
NoticeUnreadMessages
};
Q_ENUM(NoticeType);
static std::shared_ptr<ChatNoticeModel> create(std::shared_ptr<linphone::EventLog> eventLog, QObject * parent = nullptr);// Call it instead constructor
static std::shared_ptr<ChatNoticeModel> create(NoticeType noticeType, const QDateTime& timestamp,const QString& txt, QObject * parent = nullptr);
ChatNoticeModel (std::shared_ptr<linphone::EventLog> eventLog, QObject * parent = nullptr);
ChatNoticeModel (NoticeType noticeType, const QDateTime& timestamp, const QString& txt, QObject * parent = nullptr);
virtual ~ChatNoticeModel();
Q_PROPERTY(ChatRoomModel::EntryType type MEMBER mType CONSTANT)
Q_PROPERTY(ChatRoomModel::EntryType type MEMBER mType CONSTANT)// NoticeEntry
Q_PROPERTY(QDateTime timestamp MEMBER mTimestamp CONSTANT)
Q_PROPERTY(QString name MEMBER mName WRITE setName NOTIFY nameChanged)
Q_PROPERTY(NoticeType status MEMBER mStatus WRITE setStatus NOTIFY statusChanged)

View file

@ -205,6 +205,7 @@ ChatRoomModel::ChatRoomModel (std::shared_ptr<linphone::ChatRoom> chatRoom, QObj
QElapsedTimer timer;
timer.start();
CoreHandlers *coreHandlers = mCoreHandlers.get();
QObject::connect(this, &ChatRoomModel::messageSent, this, &ChatRoomModel::resetMessageCount);
//QObject::connect(coreHandlers, &CoreHandlers::messageReceived, this, &ChatRoomModel::handleMessageReceived);
QObject::connect(coreHandlers, &CoreHandlers::callCreated, this, &ChatRoomModel::handleCallCreated);
QObject::connect(coreHandlers, &CoreHandlers::callStateChanged, this, &ChatRoomModel::handleCallStateChanged);
@ -482,6 +483,10 @@ bool ChatRoomModel::haveEncryption() const{
return mChatRoom && mChatRoom->getCurrentParams()->getEncryptionBackend() != linphone::ChatRoomEncryptionBackend::None;
}
bool ChatRoomModel::markAsReadEnabled() const{
return mMarkAsReadEnabled;
}
bool ChatRoomModel::isSecure() const{
return mChatRoom && (mChatRoom->getSecurityLevel() == linphone::ChatRoomSecurityLevel::Encrypted
|| mChatRoom->getSecurityLevel() == linphone::ChatRoomSecurityLevel::Safe);
@ -514,11 +519,11 @@ bool ChatRoomModel::isCurrentProxy() const{
bool ChatRoomModel::canHandleParticipants() const{
return mChatRoom->canHandleParticipants();
}
/*
bool ChatRoomModel::getIsRemoteComposing () const {
return mIsRemoteComposing;
return mComposers.size() > 0;
}
*/
std::shared_ptr<linphone::ChatRoom> ChatRoomModel::getChatRoom(){
return mChatRoom;
@ -603,6 +608,13 @@ void ChatRoomModel::setEphemeralLifetime(long lifetime){
}
}
void ChatRoomModel::enableMarkAsRead(const bool& enable){
if( mMarkAsReadEnabled != enable){
mMarkAsReadEnabled = enable;
emit markAsReadEnabledChanged();
}
}
void ChatRoomModel::setReply(ChatMessageModel * model){
if(model != mReplyModel.get()){
if( model && model->getChatMessage() )
@ -738,10 +750,16 @@ void ChatRoomModel::compose () {
}
void ChatRoomModel::resetMessageCount () {
if(mChatRoom && !mDeleteChatRoom){
if(mChatRoom && !mDeleteChatRoom && markAsReadEnabled()){
if (mChatRoom->getUnreadMessagesCount() > 0){
mChatRoom->markAsRead();// Marking as read is only for messages. Not for calls.
}
if(!mUnreadMessageNotice.first)
mUnreadMessageNotice.first = true;
else if( mUnreadMessageNotice.second){
removeEntry(mUnreadMessageNotice.second.get());
mUnreadMessageNotice.second = nullptr;
}
setUnreadMessagesCount(mChatRoom->getUnreadMessagesCount());
setMissedCallsCount(0);
emit messageCountReset();
@ -831,9 +849,14 @@ void ChatRoomModel::initEntries(){
// On call : reinitialize all entries. This allow to free up memory
QList<std::shared_ptr<ChatEvent> > entries;
QList<EntrySorterHelper> prepareEntries;
QDateTime lastUnreadMessage = QDateTime::currentDateTime();
// Get chat messages
for (auto &message : mChatRoom->getHistory(mLastEntriesStep))
for (auto &message : mChatRoom->getHistory(mLastEntriesStep)) {
prepareEntries << EntrySorterHelper(message->getTime() ,MessageEntry, message);
if( !message->isRead()) {
lastUnreadMessage = min(lastUnreadMessage, QDateTime::fromMSecsSinceEpoch(message->getTime() * 1000));
}
}
// Get events
for(auto &eventLog : mChatRoom->getHistoryEvents(mLastEntriesStep))
prepareEntries << EntrySorterHelper(eventLog->getCreationTime() , NoticeEntry, eventLog);
@ -852,6 +875,12 @@ void ChatRoomModel::initEntries(){
}
EntrySorterHelper::getLimitedSelection(&entries, prepareEntries, mLastEntriesStep, this);
if( mChatRoom->getUnreadMessagesCount() > 0) {
mUnreadMessageNotice.first = false;
mUnreadMessageNotice.second = ChatNoticeModel::create(ChatNoticeModel::NoticeType::NoticeUnreadMessages, lastUnreadMessage, QString::number(mChatRoom->getUnreadMessagesCount()));
entries.push_front(mUnreadMessageNotice.second);
}
mIsInitialized = true;
if(entries.size() >0){
beginResetModel();
@ -914,7 +943,7 @@ int ChatRoomModel::loadMoreEntries(){
bool haveEntry = false;
while(!haveEntry && itEntries != mEntries.end()){
auto entry = dynamic_cast<ChatNoticeModel*>(itEntries->get());
haveEntry = (entry && entry->getEventLog() == eventLog);
haveEntry = (entry && entry->getEventLog() && entry->getEventLog() == eventLog);
++itEntries;
}
if(!haveEntry)
@ -1057,6 +1086,12 @@ void ChatRoomModel::insertNotices (const QList<std::shared_ptr<linphone::EventLo
}
}
}
// -----------------------------------------------------------------------------
/*
void ChatRoomModel::removeUnreadMessagesNotice() {
}*/
// -----------------------------------------------------------------------------
void ChatRoomModel::handleCallStateChanged (const std::shared_ptr<linphone::Call> &call, linphone::Call::State state) {

View file

@ -134,7 +134,7 @@ public:
Q_PROPERTY(bool isMeAdmin READ isMeAdmin NOTIFY isMeAdminChanged)
Q_PROPERTY(bool canHandleParticipants READ canHandleParticipants CONSTANT)
//Q_PROPERTY(bool isComposing MEMBER mIsRemoteComposing NOTIFY isRemoteComposingChanged)
Q_PROPERTY(bool isComposing READ getIsRemoteComposing NOTIFY isRemoteComposingChanged)
Q_PROPERTY(QList<QString> composers READ getComposers NOTIFY isRemoteComposingChanged)
Q_PROPERTY(bool hasBeenLeft READ hasBeenLeft NOTIFY hasBeenLeftChanged)
@ -148,6 +148,7 @@ public:
Q_PROPERTY(long ephemeralLifetime READ getEphemeralLifetime WRITE setEphemeralLifetime NOTIFY ephemeralLifetimeChanged)
Q_PROPERTY(bool ephemeralEnabled READ isEphemeralEnabled WRITE setEphemeralEnabled NOTIFY ephemeralEnabledChanged)
Q_PROPERTY(bool canBeEphemeral READ canBeEphemeral NOTIFY canBeEphemeralChanged)
Q_PROPERTY(bool markAsReadEnabled READ markAsReadEnabled WRITE enableMarkAsRead NOTIFY markAsReadEnabledChanged)
Q_PROPERTY(ParticipantListModel* participants READ getParticipants CONSTANT)
@ -187,6 +188,7 @@ public:
long getEphemeralLifetime() const;
bool canBeEphemeral();
bool haveEncryption() const;
bool markAsReadEnabled() const;
Q_INVOKABLE bool isSecure() const;
int getSecurityLevel() const;
bool isGroupEnabled() const;
@ -211,6 +213,7 @@ public:
void addMissedCallsCount(std::shared_ptr<linphone::Call> call);
void setEphemeralEnabled(bool enabled);
void setEphemeralLifetime(long lifetime);
void enableMarkAsRead(const bool& enable);
void setReply(ChatMessageModel * model);
ChatMessageModel * getReply()const;
@ -237,6 +240,7 @@ public:
bool mDeleteChatRoom = false; // Use as workaround because of core->deleteChatRoom() that call destructor without takking account of count ref : call it in ChatRoomModel destructor
int mLastEntriesStep = 50; // Retrieve a part of the history to avoid too much processing
bool mMarkAsReadEnabled = true;
void insertCall (const std::shared_ptr<linphone::CallLog> &callLog);
@ -312,6 +316,7 @@ signals:
void ephemeralEnabledChanged();
void ephemeralLifetimeChanged();
void canBeEphemeralChanged();
void markAsReadEnabledChanged();
void chatRoomDeleted();// Must be connected with DirectConnection mode
void replyChanged();
@ -337,7 +342,7 @@ private:
//void handleMessageReceived (const std::shared_ptr<linphone::ChatMessage> &message);
//bool mIsRemoteComposing = false;
QPair<bool, std::shared_ptr<ChatEvent> > mUnreadMessageNotice;
QList<std::shared_ptr<ChatEvent> > mEntries;
std::shared_ptr<ParticipantListModel> mParticipantListModel;
std::shared_ptr<CoreHandlers> mCoreHandlers;

View file

@ -76,6 +76,7 @@ private:
ChatRoomProxyModel::ChatRoomProxyModel (QObject *parent) : QSortFilterProxyModel(parent) {
setSourceModel(new ChatRoomModelFilter(this));
mMarkAsReadEnabled = true;
//mIsSecure = false;
App *app = App::getInstance();
@ -240,6 +241,14 @@ void ChatRoomProxyModel::setFullLocalAddress (const QString &localAddress) {
//reload();
}
bool ChatRoomProxyModel::markAsReadEnabled() const{
return mChatRoomModel->markAsReadEnabled();
}
void ChatRoomProxyModel::enableMarkAsRead(const bool& enable){
mChatRoomModel->enableMarkAsRead(enable);
}
QList<QString> ChatRoomProxyModel::getComposers() const{
return (mChatRoomModel?mChatRoomModel->getComposers():QList<QString>());
}
@ -266,6 +275,7 @@ void ChatRoomProxyModel::reload (ChatRoomModel *chatRoomModel) {
QObject::disconnect(ChatRoomModel, &ChatRoomModel::isRemoteComposingChanged, this, &ChatRoomProxyModel::handleIsRemoteComposingChanged);
QObject::disconnect(ChatRoomModel, &ChatRoomModel::messageReceived, this, &ChatRoomProxyModel::handleMessageReceived);
QObject::disconnect(ChatRoomModel, &ChatRoomModel::messageSent, this, &ChatRoomProxyModel::handleMessageSent);
QObject::disconnect(ChatRoomModel, &ChatRoomModel::markAsReadEnabledChanged, this, &ChatRoomProxyModel::markAsReadEnabledChanged);
}
@ -276,7 +286,8 @@ void ChatRoomProxyModel::reload (ChatRoomModel *chatRoomModel) {
ChatRoomModel *ChatRoomModel = mChatRoomModel.get();
QObject::connect(ChatRoomModel, &ChatRoomModel::isRemoteComposingChanged, this, &ChatRoomProxyModel::handleIsRemoteComposingChanged);
QObject::connect(ChatRoomModel, &ChatRoomModel::messageReceived, this, &ChatRoomProxyModel::handleMessageReceived);
QObject::connect(ChatRoomModel, &ChatRoomModel::messageSent, this, &ChatRoomProxyModel::handleMessageSent);
QObject::connect(ChatRoomModel, &ChatRoomModel::messageSent, this, &ChatRoomProxyModel::handleMessageSent);
QObject::connect(ChatRoomModel, &ChatRoomModel::markAsReadEnabledChanged, this, &ChatRoomProxyModel::markAsReadEnabledChanged);
}
static_cast<ChatRoomModelFilter *>(sourceModel())->setSourceModel(mChatRoomModel.get());
@ -324,7 +335,7 @@ static inline QWindow *getParentWindow (QObject *object) {
}
void ChatRoomProxyModel::handleIsActiveChanged (QWindow *window) {
if (mChatRoomModel && window->isActive() && getParentWindow(this) == window) {
if (markAsReadEnabled() && mChatRoomModel && window->isActive() && getParentWindow(this) == window) {
auto timeline = CoreManager::getInstance()->getTimelineListModel()->getTimeline(mChatRoomModel->getChatRoom(), false);
if(timeline && timeline->mSelected){
mChatRoomModel->resetMessageCount();

View file

@ -47,6 +47,7 @@ class ChatRoomProxyModel : public QSortFilterProxyModel {
Q_PROPERTY(QString cachedText READ getCachedText)
Q_PROPERTY(QString filterText MEMBER mFilterText WRITE setFilterText NOTIFY filterTextChanged)
Q_PROPERTY(bool markAsReadEnabled READ markAsReadEnabled WRITE enableMarkAsRead NOTIFY markAsReadEnabledChanged)// Focus is at end of the list. Used to reset message count if not at end
public:
ChatRoomProxyModel (QObject *parent = Q_NULLPTR);
@ -78,6 +79,7 @@ signals:
void fullPeerAddressChanged (const QString &fullPeerAddress);
void fullLocalAddressChanged (const QString &fullLocalAddress);
bool isRemoteComposingChanged ();
void markAsReadEnabledChanged();
//bool isSecureChanged(bool secure);
void chatRoomModelChanged();
@ -104,6 +106,9 @@ private:
QString getFullLocalAddress () const;
void setFullLocalAddress (const QString &localAddress);
bool markAsReadEnabled() const;
void enableMarkAsRead(const bool& enable);
//bool isSecure () const;
//void setIsSecure (const int &secure);
@ -129,6 +134,7 @@ private:
QString mFullPeerAddress;
QString mFullLocalAddress;
static QString gCachedText;
bool mMarkAsReadEnabled;
QString mFilterText;

View file

@ -6,28 +6,51 @@ import Common 1.0
// =============================================================================
ListView {
id: view
// ---------------------------------------------------------------------------
ScrollBar.vertical: ForceScrollBar {
id: vScrollBar
onPressedChanged: pressed ? view.movementStarted() : view.movementEnded()
// ScrollBar.AsNeeded doesn't work. Do it ourself.
policy: (view.contentHeight > view.height ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff)
}
// ---------------------------------------------------------------------------
boundsBehavior: Flickable.StopAtBounds
clip: true
contentWidth: width - (vScrollBar.visible?vScrollBar.width:0)
spacing: 0
synchronousDrag: true
cacheBuffer: height
// ---------------------------------------------------------------------------
// TODO: Find a solution at this bug =>
// https://bugreports.qt.io/browse/QTBUG-31573
// https://bugreports.qt.io/browse/QTBUG-49989
id: view
function getVisibleIndex(checkMax) {
var center_x = view.x + view.width / 2
var index = -1
var yCheck = 0
var direction = checkMax ? -1 : 1
var yStart = view.y + view.contentY + (checkMax ? view.height : 0)
var yStep = 5
while(index<0 && yCheck < view.height){
index = indexAt( center_x, yStart + yCheck * direction)
yCheck += yStep
}
return index
}
function getVisibleIndexRange() {
return [getVisibleIndex(0), getVisibleIndex(1)]
}
function isIndexVisible(index){
return getVisibleIndex(0) <= index && index <= getVisibleIndex(1)
}
function isIndexAfter(index){
return getVisibleIndex(1) < index
}
// ---------------------------------------------------------------------------
ScrollBar.vertical: ForceScrollBar {
id: vScrollBar
onPressedChanged: pressed ? view.movementStarted() : view.movementEnded()
// ScrollBar.AsNeeded doesn't work. Do it ourself.
policy: (view.contentHeight > view.height ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff)
}
// ---------------------------------------------------------------------------
boundsBehavior: Flickable.StopAtBounds
clip: true
contentWidth: width - (vScrollBar.visible?vScrollBar.width:0)
spacing: 0
synchronousDrag: true
cacheBuffer: height
// ---------------------------------------------------------------------------
// TODO: Find a solution at this bug =>
// https://bugreports.qt.io/browse/QTBUG-31573
// https://bugreports.qt.io/browse/QTBUG-49989
}

View file

@ -296,13 +296,19 @@ Rectangle {
}
}
footer: Item{
implicitHeight: composersItem.implicitHeight
width: parent.width
Text {
property var composers : container.proxyModel.composers
id: composersItem
property var composers : container.proxyModel.chatRoomModel.composers
onComposersChanged: console.log(composers)
onVisibleChanged: console.log(visible)
color: ChatStyle.composingText.color
font.pointSize: ChatStyle.composingText.pointSize
height: visible ? undefined : 0
leftPadding: ChatStyle.composingText.leftPadding
visible: composers.length > 0 && (!proxyModel.chatRoomModel.haveEncryption && SettingsModel.standardChatEnabled || proxyModel.chatRoomModel.haveEncryption && SettingsModel.secureChatEnabled)
visible: composers.length > 0 && ( (!proxyModel.chatRoomModel.haveEncryption && SettingsModel.standardChatEnabled)
|| (proxyModel.chatRoomModel.haveEncryption && SettingsModel.secureChatEnabled) )
wrapMode: Text.Wrap
//: '%1 is typing...' indicate that someone is composing in chat
text:(composers.length==0?'': qsTr('chatTyping','',composers.length).arg(container.proxyModel.getDisplayNameComposers()))
@ -315,7 +321,7 @@ Rectangle {
}
Rectangle{
id: messageBlock
height: 32
height: opacity > 0 ? 32 : 0
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
@ -375,6 +381,31 @@ Rectangle {
}
]
}
ActionButton{
anchors.bottom: messageBlock.top
anchors.bottomMargin: 10
anchors.right: parent.right
anchors.rightMargin: 40
visible: chat.isIndexAfter(chat.count-1)
onVisibleChanged: container.proxyModel.markAsReadEnabled = !visible
isCustom: true
backgroundRadius: width/2
colorSet: ChatStyle.gotToBottom
onClicked: {
chat.bindToEnd = true
}
MessageCounter{
anchors.left: parent.right
anchors.bottom: parent.top
anchors.bottomMargin: -5
anchors.leftMargin: -5
count: container.proxyModel.chatRoomModel.unreadMessagesCount
}
}
}
// -------------------------------------------------------------------------

View file

@ -15,6 +15,11 @@ RowLayout{
id: mainLayout
property string _type: {
var status = $chatEntry.eventLogType
var type = $chatEntry.status
if(type == ChatNoticeModel.NoticeUnreadMessages)
//: '%1 unread messages' : Little message to show on an event where unread messages begin.
return qsTr('unreadMessageNotice', '', $chatEntry.name)
if (status == LinphoneEnums.EventLogTypeConferenceCreated) {
//: 'You have joined the group' : Little message to show on the event when the user join the chat group.

View file

@ -26,6 +26,18 @@ QtObject {
}
}
property QtObject gotToBottom: QtObject{
property string name: 'goToBottom'
property string icon: 'move_to_bottom_custom'
property int iconSize: 30
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_b_n', icon, 's_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_b_h', icon, 's_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_b_p', icon, 's_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_f_n', icon, 's_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_f_h', icon, 's_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_f_p', icon, 's_p_b_fg').color
}
property QtObject sendArea: QtObject {
property int height: 80

@ -1 +1 @@
Subproject commit 3d422c64a3a10289fe6dda31ccb0af17b41cfffa
Subproject commit 5800f6e489b250c5ffccaa90c8771a10a9edad59