diff --git a/ui/models/element.cpp b/ui/models/element.cpp index 659a30f..4bdc3d7 100644 --- a/ui/models/element.cpp +++ b/ui/models/element.cpp @@ -31,6 +31,8 @@ Models::Element::Element(Type p_type, const Models::Account* acc, const QString& { connect(feed, &MessageFeed::requestArchive, this, &Element::requestArchive); connect(feed, &MessageFeed::fileDownloadRequest, this, &Element::fileDownloadRequest); + connect(feed, &MessageFeed::unreadMessagesCountChanged, this, &Element::onFeedUnreadMessagesCountChanged); + connect(feed, &MessageFeed::unnoticedMessage, this, &Element::onFeedUnnoticedMessage); QMap::const_iterator itr = data.find("avatarState"); if (itr != data.end()) { @@ -134,11 +136,6 @@ unsigned int Models::Element::getMessagesCount() const void Models::Element::addMessage(const Shared::Message& data) { feed->addMessage(data); - if (type == contact) { - changed(4); - } else if (type == room) { - changed(5); - } } void Models::Element::changeMessage(const QString& id, const QMap& data) @@ -170,3 +167,17 @@ void Models::Element::fileError(const QString& messageId, const QString& error, { feed->fileError(messageId, error, up); } + +void Models::Element::onFeedUnreadMessagesCountChanged() +{ + if (type == contact) { + changed(4); + } else if (type == room) { + changed(5); + } +} + +void Models::Element::onFeedUnnoticedMessage(const Shared::Message& msg) +{ + emit unnoticedMessage(getAccountName(), msg); +} diff --git a/ui/models/element.h b/ui/models/element.h index db6cda1..1818405 100644 --- a/ui/models/element.h +++ b/ui/models/element.h @@ -50,6 +50,7 @@ public: signals: void requestArchive(const QString& before); void fileDownloadRequest(const QString& url); + void unnoticedMessage(const QString& account, const Shared::Message& msg); protected: void setJid(const QString& p_jid); @@ -59,6 +60,10 @@ protected: bool columnInvolvedInDisplay(int col) override; const Account* getParentAccount() const override; +protected slots: + void onFeedUnreadMessagesCountChanged(); + void onFeedUnnoticedMessage(const Shared::Message& msg); + protected: QString jid; QString avatarPath; diff --git a/ui/models/messagefeed.cpp b/ui/models/messagefeed.cpp index c3a7923..07dfe0a 100644 --- a/ui/models/messagefeed.cpp +++ b/ui/models/messagefeed.cpp @@ -44,12 +44,16 @@ Models::MessageFeed::MessageFeed(const Element* ri, QObject* parent): rosterItem(ri), syncState(incomplete), uploads(), - downloads() + downloads(), + unreadMessages(new std::set()), + observersAmount(0) { } Models::MessageFeed::~MessageFeed() { + delete unreadMessages; + for (Shared::Message* message : storage) { delete message; } @@ -75,6 +79,14 @@ void Models::MessageFeed::addMessage(const Shared::Message& msg) beginInsertRows(QModelIndex(), position, position); storage.insert(copy); endInsertRows(); + + emit newMessage(msg); + + if (observersAmount == 0 && !msg.getForwarded()) { //not to notify when the message is delivered by the carbon copy + unreadMessages->insert(msg.getId()); //cuz it could be my own one or the one I read on another device + emit unreadMessagesCountChanged(); + emit unnoticedMessage(msg); + } } void Models::MessageFeed::changeMessage(const QString& id, const QMap& data) @@ -97,6 +109,11 @@ void Models::MessageFeed::changeMessage(const QString& id, const QMap::const_iterator umi = unreadMessages->find(id); + if (umi != unreadMessages->end()) { + unreadMessages->erase(umi); + unreadMessages->insert(msg->getId()); + } } //change message is a final event in download/upload event train @@ -258,6 +275,13 @@ QVariant Models::MessageFeed::data(const QModelIndex& index, int role) const case Bulk: { FeedItem item; item.id = msg->getId(); + + std::set::const_iterator umi = unreadMessages->find(item.id); + if (umi != unreadMessages->end()) { + unreadMessages->erase(umi); + emit unreadMessagesCount(); + } + item.sentByMe = sentByMe(*msg); item.date = msg->getTime(); item.state = msg->getState(); @@ -308,7 +332,7 @@ int Models::MessageFeed::rowCount(const QModelIndex& parent) const unsigned int Models::MessageFeed::unreadMessagesCount() const { - return storage.size(); //let's say they are all new for now =) + return unreadMessages->size(); } bool Models::MessageFeed::canFetchMore(const QModelIndex& parent) const @@ -456,6 +480,16 @@ void Models::MessageFeed::fileError(const QString& messageId, const QString& err //TODO } +void Models::MessageFeed::incrementObservers() +{ + ++observersAmount; +} + +void Models::MessageFeed::decrementObservers() +{ + --observersAmount; +} + QModelIndex Models::MessageFeed::modelIndexById(const QString& id) const { diff --git a/ui/models/messagefeed.h b/ui/models/messagefeed.h index c86df33..1b7bc43 100644 --- a/ui/models/messagefeed.h +++ b/ui/models/messagefeed.h @@ -66,10 +66,16 @@ public: void fileError(const QString& messageId, const QString& error, bool up); void fileComplete(const QString& messageId, bool up); + void incrementObservers(); + void decrementObservers(); + signals: void requestArchive(const QString& before); void requestStateChange(bool requesting); void fileDownloadRequest(const QString& url); + void unreadMessagesCountChanged(); + void newMessage(const Shared::Message& msg); + void unnoticedMessage(const Shared::Message& msg); public: enum MessageRoles { @@ -140,6 +146,9 @@ private: Progress uploads; Progress downloads; + std::set* unreadMessages; + uint16_t observersAmount; + static const QHash roles; }; diff --git a/ui/models/roster.cpp b/ui/models/roster.cpp index 5e3a1ac..eb02942 100644 --- a/ui/models/roster.cpp +++ b/ui/models/roster.cpp @@ -448,6 +448,7 @@ void Models::Roster::addContact(const QString& account, const QString& jid, cons contact = new Contact(acc, jid, data); connect(contact, &Contact::requestArchive, this, &Roster::onElementRequestArchive); connect(contact, &Contact::fileDownloadRequest, this, &Roster::fileDownloadRequest); + connect(contact, &Contact::unnoticedMessage, this, &Roster::unnoticedMessage); contacts.insert(std::make_pair(id, contact)); } else { contact = itr->second; @@ -785,6 +786,7 @@ void Models::Roster::addRoom(const QString& account, const QString jid, const QM Room* room = new Room(acc, jid, data); connect(room, &Contact::requestArchive, this, &Roster::onElementRequestArchive); connect(room, &Contact::fileDownloadRequest, this, &Roster::fileDownloadRequest); + connect(room, &Contact::unnoticedMessage, this, &Roster::unnoticedMessage); rooms.insert(std::make_pair(id, room)); acc->appendChild(room); } diff --git a/ui/models/roster.h b/ui/models/roster.h index 775d8de..10da0fb 100644 --- a/ui/models/roster.h +++ b/ui/models/roster.h @@ -92,6 +92,7 @@ public: signals: void requestArchive(const QString& account, const QString& jid, const QString& before); void fileDownloadRequest(const QString& url); + void unnoticedMessage(const QString& account, const Shared::Message& msg); private: Element* getElement(const ElId& id); diff --git a/ui/squawk.cpp b/ui/squawk.cpp index 05f8c87..d7085aa 100644 --- a/ui/squawk.cpp +++ b/ui/squawk.cpp @@ -59,6 +59,7 @@ Squawk::Squawk(QWidget *parent) : connect(m_ui->roster, &QTreeView::customContextMenuRequested, this, &Squawk::onRosterContextMenu); connect(m_ui->roster, &QTreeView::collapsed, this, &Squawk::onItemCollepsed); connect(m_ui->roster->selectionModel(), &QItemSelectionModel::currentRowChanged, this, &Squawk::onRosterSelectionChanged); + connect(&rosterModel, &Models::Roster::unnoticedMessage, this, &Squawk::onUnnoticedMessage); connect(rosterModel.accountsModel, &Models::Accounts::sizeChanged, this, &Squawk::onAccountsSizeChanged); connect(&rosterModel, &Models::Roster::requestArchive, this, &Squawk::onRequestArchive); @@ -410,36 +411,13 @@ void Squawk::fileUploadComplete(const std::list msgs, const void Squawk::accountMessage(const QString& account, const Shared::Message& data) { - const QString& from = data.getPenPalJid(); - Models::Roster::ElId id({account, from}); - Conversations::iterator itr = conversations.find(id); - bool found = false; - rosterModel.addMessage(account, data); - - if (currentConversation != 0 && currentConversation->getId() == id) { - QApplication::alert(this); - if (!isVisible() && !data.getForwarded()) { - notify(account, data); - } - found = true; - } - - if (itr != conversations.end()) { - Conversation* conv = itr->second; - QApplication::alert(conv); - if (!conv->isVisible() && !data.getForwarded()) { - notify(account, data); - } - found = true; - } - - if (!found) { - if (!data.getForwarded()) { - QApplication::alert(this); - notify(account, data); - } - } +} + +void Squawk::onUnnoticedMessage(const QString& account, const Shared::Message& msg) +{ + notify(account, msg); //Telegram does this way - notifies even if the app is visible + QApplication::alert(this); } void Squawk::changeMessage(const QString& account, const QString& jid, const QString& id, const QMap& data) @@ -935,6 +913,7 @@ void Squawk::subscribeConversation(Conversation* conv) { connect(conv, &Conversation::destroyed, this, &Squawk::onConversationClosed); connect(conv, &Conversation::sendMessage, this, &Squawk::onConversationMessage); + connect(conv, &Conversation::notifyableMessage, this, &Squawk::notify); } void Squawk::onRosterSelectionChanged(const QModelIndex& current, const QModelIndex& previous) diff --git a/ui/squawk.h b/ui/squawk.h index ada13fc..cda7c8c 100644 --- a/ui/squawk.h +++ b/ui/squawk.h @@ -128,6 +128,8 @@ private: protected: void closeEvent(QCloseEvent * event) override; + +protected slots: void notify(const QString& account, const Shared::Message& msg); private slots: @@ -153,6 +155,8 @@ private slots: void onRosterSelectionChanged(const QModelIndex& current, const QModelIndex& previous); void onContextAboutToHide(); + void onUnnoticedMessage(const QString& account, const Shared::Message& msg); + private: void checkNextAccountForPassword(); void onPasswordPromptDone(); diff --git a/ui/widgets/chat.cpp b/ui/widgets/chat.cpp index 1b20e86..052d83d 100644 --- a/ui/widgets/chat.cpp +++ b/ui/widgets/chat.cpp @@ -71,15 +71,14 @@ Shared::Message Chat::createMessage() const return msg; } -// TODO -// void Chat::addMessage(const Shared::Message& data) -// { -// Conversation::addMessage(data); -// -// if (!data.getOutgoing()) { //TODO need to check if that was the last message -// const QString& res = data.getPenPalResource(); -// if (res.size() > 0) { -// setPalResource(res); -// } -// } -// } +void Chat::onMessage(const Shared::Message& data) +{ + Conversation::onMessage(data); + + if (!data.getOutgoing()) { + const QString& res = data.getPenPalResource(); + if (res.size() > 0) { + setPalResource(res); + } + } +} diff --git a/ui/widgets/chat.h b/ui/widgets/chat.h index c0be972..78e6bec 100644 --- a/ui/widgets/chat.h +++ b/ui/widgets/chat.h @@ -34,14 +34,13 @@ class Chat : public Conversation public: Chat(Models::Account* acc, Models::Contact* p_contact, QWidget* parent = 0); ~Chat(); - - //void addMessage(const Shared::Message & data) override; protected slots: void onContactChanged(Models::Item* item, int row, int col); protected: Shared::Message createMessage() const override; + void onMessage(const Shared::Message& msg) override; private: void updateState(); diff --git a/ui/widgets/conversation.cpp b/ui/widgets/conversation.cpp index d6e3c9a..7e4b138 100644 --- a/ui/widgets/conversation.cpp +++ b/ui/widgets/conversation.cpp @@ -48,8 +48,6 @@ Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el, delegate(new MessageDelegate(this)), scroll(down), manualSliderChange(false), - requestingHistory(false), - everShown(false), tsb(QApplication::style()->styleHint(QStyle::SH_ScrollBar_Transient) == 1) { m_ui->setupUi(this); @@ -57,8 +55,11 @@ Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el, feed->setItemDelegate(delegate); delegate->initializeFonts(feed->getFont()); feed->setModel(el->feed); + el->feed->incrementObservers(); m_ui->widget->layout()->addWidget(feed); + connect(el->feed, &Models::MessageFeed::newMessage, this, &Conversation::onFeedMessage); + connect(acc, &Models::Account::childChanged, this, &Conversation::onAccountChanged); filesLayout = new FlowLayout(m_ui->filesPanel, 0); @@ -69,9 +70,6 @@ Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el, connect(&ker, &KeyEnterReceiver::enterPressed, this, &Conversation::onEnterPressed); connect(m_ui->sendButton, &QPushButton::clicked, this, &Conversation::onEnterPressed); - //connect(line, &MessageLine::downloadFile, this, &Conversation::downloadFile); - //connect(line, &MessageLine::uploadFile, this, qOverload(&Conversation::sendMessage)); - //connect(line, &MessageLine::requestLocalFile, this, &Conversation::requestLocalFile); connect(m_ui->attachButton, &QPushButton::clicked, this, &Conversation::onAttach); connect(m_ui->clearButton, &QPushButton::clicked, this, &Conversation::onClearButton); connect(m_ui->messageEditor->document()->documentLayout(), &QAbstractTextDocumentLayout::documentSizeChanged, @@ -121,18 +119,19 @@ Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el, Conversation::~Conversation() { + element->feed->decrementObservers(); } void Conversation::onAccountChanged(Models::Item* item, int row, int col) { if (item == account) { - if (col == 2 && account->getState() == Shared::ConnectionState::connected) { - if (!requestingHistory) { - requestingHistory = true; + if (col == 2 && account->getState() == Shared::ConnectionState::connected) { //to request the history when we're back online after reconnect + //if (!requestingHistory) { + //requestingHistory = true; //line->showBusyIndicator(); //emit requestArchive(""); //scroll = down; - } + //} } } } @@ -223,21 +222,6 @@ void Conversation::onEnterPressed() } } -void Conversation::showEvent(QShowEvent* event) -{ - if (!everShown) { - everShown = true; -// line->showBusyIndicator(); - requestingHistory = true; - scroll = keep; - emit requestArchive(""); - } - emit shown(); - - QWidget::showEvent(event); - -} - void Conversation::onAttach() { QFileDialog* d = new QFileDialog(this, tr("Chose a file to send")); @@ -265,21 +249,6 @@ void Conversation::setStatus(const QString& status) statusLabel->setText(Shared::processMessageBody(status)); } -void Conversation::responseFileProgress(const QString& messageId, qreal progress) -{ -// line->fileProgress(messageId, progress); -} - -void Conversation::fileError(const QString& messageId, const QString& error) -{ -// line->fileError(messageId, error); -} - -void Conversation::responseLocalFile(const QString& messageId, const QString& path) -{ -// line->responseLocalFile(messageId, path); -} - Models::Roster::ElId Conversation::getId() const { return {getAccount(), getJid()}; @@ -416,3 +385,18 @@ Shared::Message Conversation::createMessage() const return msg; } +void Conversation::onFeedMessage(const Shared::Message& msg) +{ + this->onMessage(msg); +} + +void Conversation::onMessage(const Shared::Message& msg) +{ + qDebug() << window()->windowState(); + if (!msg.getForwarded()) { + QApplication::alert(this); + if (window()->windowState().testFlag(Qt::WindowMinimized)) { + emit notifyableMessage(getAccount(), msg); + } + } +} diff --git a/ui/widgets/conversation.h b/ui/widgets/conversation.h index b506e39..1c81d31 100644 --- a/ui/widgets/conversation.h +++ b/ui/widgets/conversation.h @@ -68,10 +68,6 @@ public: Models::Roster::ElId getId() const; void setPalResource(const QString& res); - void showEvent(QShowEvent * event) override; - void responseLocalFile(const QString& messageId, const QString& path); - void fileError(const QString& messageId, const QString& error); - void responseFileProgress(const QString& messageId, qreal progress); virtual void setAvatar(const QString& path); void setFeedFrames(bool top, bool right, bool bottom, bool left); @@ -81,6 +77,7 @@ signals: void shown(); void requestLocalFile(const QString& messageId, const QString& url); void downloadFile(const QString& messageId, const QString& url); + void notifyableMessage(const QString& account, const Shared::Message& msg); protected: virtual void setName(const QString& name); @@ -93,6 +90,7 @@ protected: void dragEnterEvent(QDragEnterEvent* event) override; void dragLeaveEvent(QDragLeaveEvent* event) override; void dropEvent(QDropEvent* event) override; + virtual void onMessage(const Shared::Message& msg); protected slots: void onEnterPressed(); @@ -102,6 +100,7 @@ protected slots: void onClearButton(); void onTextEditDocSizeChanged(const QSizeF& size); void onAccountChanged(Models::Item* item, int row, int col); + void onFeedMessage(const Shared::Message& msg); public: const bool isMuc; @@ -128,8 +127,6 @@ protected: MessageDelegate* delegate; Scroll scroll; bool manualSliderChange; - bool requestingHistory; - bool everShown; bool tsb; //transient scroll bars };