diff --git a/src/conversationlistmodel.cpp b/src/conversationlistmodel.cpp index fd0b16c0a83452abdaf7aa89c0e5ce2c745f9e97..355c79cdc5c7d442ff7de5acf997e77f4bdc26d6 100644 --- a/src/conversationlistmodel.cpp +++ b/src/conversationlistmodel.cpp @@ -105,19 +105,10 @@ ConversationListProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& s using namespace ConversationList; - // name/id - auto uri = index.data(Role::URI).toString(); - auto alias = index.data(Role::Alias).toString(); - auto registeredName = index.data(Role::RegisteredName).toString(); - - // account type - auto itemProfileType = static_cast<profile::Type>(index.data(Role::ContactType).toInt()); - // this is workaround for profile::Type including both account types and extended types - // - PENDING is implicitly also JAMI - // - TEMPORARY should never be in this list - if (itemProfileType == profile::Type::PENDING) - itemProfileType = profile::Type::JAMI; - auto typeFilter = itemProfileType == profileTypeFilter_; + QStringList toFilter; + toFilter += index.data(Role::Title).toString(); + toFilter += index.data(Role::Uris).toStringList(); + toFilter += index.data(Role::Monikers).toStringList(); // requests auto isRequest = index.data(Role::IsRequest).toBool(); @@ -127,14 +118,22 @@ ConversationListProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& s // banned contacts require exact match if (index.data(Role::IsBanned).toBool()) { - match = !rx.isEmpty() - && (rx.exactMatch(uri) || rx.exactMatch(alias) || rx.exactMatch(registeredName)); + if (!rx.isEmpty()) { + Q_FOREACH (const auto& filter, toFilter) + if (rx.exactMatch(filter)) { + match = true; + break; + } + } } else { - match = (rx.indexIn(uri) != -1 || rx.indexIn(alias) != -1 - || rx.indexIn(registeredName) != -1); + Q_FOREACH (const auto& filter, toFilter) + if (rx.indexIn(filter) != -1) { + match = true; + break; + } } - return typeFilter && requestFilter && match; + return requestFilter && match; } bool @@ -146,20 +145,6 @@ ConversationListProxyModel::lessThan(const QModelIndex& left, const QModelIndex& return leftData.toULongLong() < rightData.toULongLong(); } -void -ConversationListProxyModel::setProfileTypeFilter(const profile::Type& profileTypeFilter) -{ - if (profileTypeFilter != lrc::api::profile::Type::JAMI - && profileTypeFilter != lrc::api::profile::Type::SIP) { - qWarning() << "Profile filter parameter must be an account type"; - return; - } - beginResetModel(); - profileTypeFilter_ = profileTypeFilter; - endResetModel(); - updateSelection(); -}; - void ConversationListProxyModel::setFilterRequests(bool filterRequests) { diff --git a/src/conversationlistmodel.h b/src/conversationlistmodel.h index b41dad1fe898d04e01ff714e95bb8870dba93078..27027914de7d9604c605c151f0672458f61eb331 100644 --- a/src/conversationlistmodel.h +++ b/src/conversationlistmodel.h @@ -48,15 +48,9 @@ public: bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override; bool lessThan(const QModelIndex& left, const QModelIndex& right) const override; - Q_INVOKABLE void setProfileTypeFilter(const profile::Type& profileTypeFilter); Q_INVOKABLE void setFilterRequests(bool filterRequests); private: - // With swarm in place, this filter should only ever be set to profile::Type::JAMI - // and profile::Type::SIP as profile::Type::PENDING should no longer be used to - // filter for invites, and instead use the isRequest property of a conversation. - profile::Type profileTypeFilter_; - // This flag can be toggled when switching tabs to show the current account's // conversation invites. bool filterRequests_ {false}; diff --git a/src/conversationlistmodelbase.cpp b/src/conversationlistmodelbase.cpp index 6921dafbb66905919c981a04fba6fe8c7169b6b8..f65cff1aa706dfd0a13453ed7a7bf86be41d3903 100644 --- a/src/conversationlistmodelbase.cpp +++ b/src/conversationlistmodelbase.cpp @@ -47,70 +47,7 @@ ConversationListModelBase::roleNames() const QVariant ConversationListModelBase::dataForItem(item_t item, int role) const { - if (item.participants.isEmpty()) { - return QVariant(); - } - // WARNING: not swarm ready - auto peerUri = item.participants[0]; - ContactModel* contactModel {nullptr}; - contact::Info contact {}; - try { - const auto& accountInfo = lrcInstance_->getAccountInfo(item.accountId); - contactModel = accountInfo.contactModel.get(); - contact = contactModel->getContact(peerUri); - } catch (...) { - } - - // Since we are using image provider right now, image url representation should be unique to - // be able to use the image cache, account avatar will only be updated once PictureUid changed switch (role) { - case Role::Title: - return QVariant(model_->title(item.uid)); - case Role::BestId: - return QVariant(contactModel->bestIdForContact(peerUri)); - case Role::Presence: - return QVariant(contact.isPresent); - case Role::PictureUid: - return QVariant(contactAvatarUidMap_[peerUri]); - case Role::Alias: - return QVariant(contact.profileInfo.alias); - case Role::RegisteredName: - return QVariant(contact.registeredName); - case Role::URI: - return QVariant(peerUri); - case Role::UnreadMessagesCount: - return QVariant(item.unreadMessages); - case Role::LastInteractionTimeStamp: { - if (!item.interactions.empty()) { - auto ts = static_cast<qint32>(item.interactions.at(item.lastMessageUid).timestamp); - return QVariant(ts); - } - break; - } - case Role::LastInteractionDate: { - if (!item.interactions.empty()) { - return QVariant( - Utils::formatTimeString(item.interactions.at(item.lastMessageUid).timestamp)); - } - break; - } - case Role::LastInteraction: { - if (!item.interactions.empty()) { - return QVariant(item.interactions.at(item.lastMessageUid).body); - } - break; - } - case Role::ContactType: { - return QVariant(static_cast<int>(contact.profileInfo.type)); - } - case Role::IsSwarm: { - return QVariant(!item.isNotASwarm()); - } - case Role::IsBanned: { - return QVariant(contact.isBanned); - } - case Role::UID: - return QVariant(item.uid); case Role::InCall: { const auto& convInfo = lrcInstance_->getConversationFromConvUid(item.uid); if (!convInfo.uid.isEmpty()) { @@ -127,7 +64,7 @@ ConversationListModelBase::dataForItem(item_t item, int role) const return QVariant(call->isAudioOnly); } } - return QVariant(); + return QVariant(false); } case Role::CallStackViewShouldShow: { const auto& convInfo = lrcInstance_->getConversationFromConvUid(item.uid); @@ -150,7 +87,7 @@ ConversationListModelBase::dataForItem(item_t item, int role) const return QVariant(static_cast<int>(call->status)); } } - return QVariant(); + return {}; } case Role::Draft: { if (!item.uid.isEmpty()) { @@ -162,13 +99,94 @@ ConversationListModelBase::dataForItem(item_t item, int role) const return emojiString + draft; } } - return QVariant(""); + return {}; } - case Role::IsRequest: { + case Role::IsRequest: return QVariant(item.isRequest); + case Role::Title: + return QVariant(model_->title(item.uid)); + case Role::UnreadMessagesCount: + return QVariant(item.unreadMessages); + case Role::LastInteractionTimeStamp: { + if (!item.interactions.empty()) { + auto ts = static_cast<qint32>(item.interactions.at(item.lastMessageUid).timestamp); + return QVariant(ts); + } + break; + } + case Role::LastInteractionDate: { + if (!item.interactions.empty()) { + return QVariant( + Utils::formatTimeString(item.interactions.at(item.lastMessageUid).timestamp)); + } + break; + } + case Role::LastInteraction: { + if (!item.interactions.empty()) { + return QVariant(item.interactions.at(item.lastMessageUid).body); + } + break; } + case Role::IsSwarm: + return QVariant(item.isSwarm()); + case Role::Mode: + return QVariant(static_cast<int>(item.mode)); + case Role::UID: + return QVariant(item.uid); + case Role::Uris: + return QVariant(model_->peersForConversation(item.uid).toList()); + case Role::Monikers: { + // we shouldn't ever need these individually, they are used for filtering only + QStringList ret; + Q_FOREACH (const auto& peerUri, model_->peersForConversation(item.uid)) + try { + auto& accInfo = lrcInstance_->getCurrentAccountInfo(); + auto contact = accInfo.contactModel->getContact(peerUri); + ret << contact.profileInfo.alias << contact.registeredName; + } catch (const std::exception&) { + } + return ret; } - return QVariant(); + default: + break; + } + + if (item.isCoreDialog()) { + auto peerUriList = model_->peersForConversation(item.uid); + if (peerUriList.isEmpty()) { + return {}; + } + auto peerUri = peerUriList.at(0); + ContactModel* contactModel; + contact::Info contact {}; + try { + contactModel = lrcInstance_->getCurrentAccountInfo().contactModel.get(); + contact = contactModel->getContact(peerUri); + } catch (const std::exception&) { + return {}; + } + + switch (role) { + case Role::BestId: + return QVariant(contactModel->bestIdForContact(peerUri)); + case Role::Presence: + return QVariant(contact.isPresent); + case Role::PictureUid: + return QVariant(contactAvatarUidMap_[peerUri]); + case Role::Alias: + return QVariant(contact.profileInfo.alias); + case Role::RegisteredName: + return QVariant(contact.registeredName); + case Role::URI: + return QVariant(peerUri); + case Role::IsBanned: + return QVariant(contact.isBanned); + case Role::ContactType: + return QVariant(static_cast<int>(contact.profileInfo.type)); + } + } + + return {}; } void diff --git a/src/conversationlistmodelbase.h b/src/conversationlistmodelbase.h index 9a988bbdc5a71e871de850dc092aa88a88e3ba5f..40fc0fcd74ac45fe5fa421c47957e6f003303626 100644 --- a/src/conversationlistmodelbase.h +++ b/src/conversationlistmodelbase.h @@ -45,7 +45,10 @@ X(AccountId) \ X(PictureUid) \ X(Draft) \ - X(IsRequest) + X(IsRequest) \ + X(Mode) \ + X(Uris) \ + X(Monikers) namespace ConversationList { Q_NAMESPACE diff --git a/src/conversationsadapter.cpp b/src/conversationsadapter.cpp index ba9ca91e008863638cbe9057a7abbdbc96362a23..2d7bf6b9494d89bad08a50a06f7c002a8b89ef5d 100644 --- a/src/conversationsadapter.cpp +++ b/src/conversationsadapter.cpp @@ -44,15 +44,8 @@ ConversationsAdapter::ConversationsAdapter(SystemTray* systemTray, new SelectableListProxyGroupModel({convModel_.data(), searchModel_.data()}, this); - // this will trigger when the conversations filter tab is selected - connect(this, &ConversationsAdapter::profileTypeFilterChanged, [this]() { - convModel_->setProfileTypeFilter(profileTypeFilter_); - }); - set_profileTypeFilter(profile::Type::JAMI); - // this will trigger when the invite filter tab is selected connect(this, &ConversationsAdapter::filterRequestsChanged, [this]() { - // it is assumed that profileTypeFilter is profile::Type::JAMI here convModel_->setFilterRequests(filterRequests_); }); @@ -73,9 +66,6 @@ ConversationsAdapter::ConversationsAdapter(SystemTray* systemTray, accInfo.conversationModel->selectConversation(convInfo.uid); accInfo.conversationModel->clearUnreadInteractions(convInfo.uid); - // set the account type filter corresponding to the conversation's account type - set_profileTypeFilter(accInfo.profileInfo.type); - // this may be a request, so adjust that filter also set_filterRequests(convInfo.isRequest); @@ -161,8 +151,6 @@ ConversationsAdapter::safeInit() Qt::UniqueConnection); connectConversationModel(); - - set_profileTypeFilter(lrcInstance_->getCurrentAccountInfo().profileInfo.type); } void @@ -172,8 +160,6 @@ ConversationsAdapter::onCurrentAccountIdChanged() connectConversationModel(); - set_profileTypeFilter(lrcInstance_->getCurrentAccountInfo().profileInfo.type); - // Always turn the requests filter off when switching account. // Conversation selection will manage the filter state in the // case of programmatic selection(incoming call, notification @@ -355,9 +341,6 @@ ConversationsAdapter::updateConversationFilterData() } set_totalUnreadMessageCount(totalUnreadMessages); set_pendingRequestCount(accountInfo.conversationModel->pendingRequestCount()); - if (pendingRequestCount_ == 0 && profileTypeFilter_ == profile::Type::PENDING) { - set_profileTypeFilter(profile::Type::JAMI); - } } void @@ -408,7 +391,7 @@ ConversationsAdapter::getConvInfoMap(const QString& convId) {"bestId", contactModel->bestIdForContact(peerUri)}, {"title", lrcInstance_->getCurrentConversationModel()->title(convId)}, {"uri", peerUri}, - {"isSwarm", !convInfo.isNotASwarm()}, + {"isSwarm", convInfo.isSwarm()}, {"contactType", static_cast<int>(contact.profileInfo.type)}, {"isAudioOnly", isAudioOnly}, {"callState", static_cast<int>(callState)}, diff --git a/src/conversationsadapter.h b/src/conversationsadapter.h index 052a19129d1883a6d8f599132615e1370dbdc793..1f107c05d2d3e4a3403a711d17dccf26f4027ed4 100644 --- a/src/conversationsadapter.h +++ b/src/conversationsadapter.h @@ -33,7 +33,6 @@ class SystemTray; class ConversationsAdapter final : public QmlAdapterBase { Q_OBJECT - QML_PROPERTY(lrc::api::profile::Type, profileTypeFilter) QML_PROPERTY(bool, filterRequests) QML_PROPERTY(int, totalUnreadMessageCount) QML_PROPERTY(int, pendingRequestCount) diff --git a/src/mainview/components/SidePanelTabBar.qml b/src/mainview/components/SidePanelTabBar.qml index 1e5141c91179d31705c35346966e9eb5fcf3eae8..59babc805e3eaec762fd408b839a74676a50a384 100644 --- a/src/mainview/components/SidePanelTabBar.qml +++ b/src/mainview/components/SidePanelTabBar.qml @@ -39,7 +39,6 @@ TabBar { } function selectTab(idx) { - ConversationsAdapter.profileTypeFilter = LRCInstance.currentAccountType ConversationsAdapter.filterRequests = (idx === SidePanelTabBar.Requests) } diff --git a/src/messagesadapter.cpp b/src/messagesadapter.cpp index e49d0d83cdb293fd3a22c9175108a66bc48b37fc..d3b295fff4ea0dcd5d3601f2daf7bee660e8d0b1 100644 --- a/src/messagesadapter.cpp +++ b/src/messagesadapter.cpp @@ -80,19 +80,19 @@ MessagesAdapter::setupChatView(const QString& convUid) QMetaObject::invokeMethod(qmlObj_, "setSendContactRequestButtonVisible", - Q_ARG(QVariant, convInfo.isNotASwarm() && convInfo.isRequest)); + Q_ARG(QVariant, convInfo.isLegacy() && convInfo.isRequest)); QMetaObject::invokeMethod(qmlObj_, "setMessagingHeaderButtonsVisible", Q_ARG(QVariant, - !(convInfo.isNotASwarm() + !(convInfo.isLegacy() && (convInfo.isRequest || convInfo.needsSyncing)))); setMessagesVisibility(false); - setIsSwarm(!convInfo.isNotASwarm()); + setIsSwarm(convInfo.isSwarm()); setInvitation(convInfo.isRequest or convInfo.needsSyncing, convModel->title(convInfo.uid), contactURI, - !convInfo.isNotASwarm(), + !convInfo.isSwarm(), convInfo.needsSyncing); // Draft and message content set up. @@ -257,7 +257,7 @@ MessagesAdapter::slotMessagesCleared() auto convOpt = convModel->getConversationForUid(lrcInstance_->get_selectedConvUid()); if (!convOpt) return; - if (!convOpt->get().isNotASwarm() && !convOpt->get().allMessagesLoaded) { + if (convOpt->get().isSwarm() && !convOpt->get().allMessagesLoaded) { convModel->loadConversationMessages(convOpt->get().uid, 20); } else { printHistory(*convModel, convOpt->get().interactions); @@ -504,15 +504,15 @@ MessagesAdapter::setConversationProfileData(const lrc::api::conversation::Info& QMetaObject::invokeMethod(qmlObj_, "setMessagingHeaderButtonsVisible", Q_ARG(QVariant, - !(!convInfo.isNotASwarm() + !(convInfo.isSwarm() && (convInfo.isRequest || convInfo.needsSyncing)))); setInvitation(convInfo.isRequest or convInfo.needsSyncing, title, contactUri, - !convInfo.isNotASwarm(), + convInfo.isSwarm(), convInfo.needsSyncing); - if (!convInfo.isNotASwarm()) + if (convInfo.isSwarm()) return; auto& contact = accInfo->contactModel->getContact(contactUri); bool isPending = contact.profileInfo.type == profile::Type::TEMPORARY; @@ -811,6 +811,6 @@ MessagesAdapter::loadMessages(int n) auto convOpt = convModel->getConversationForUid(currentConvUid_); if (!convOpt) return; - if (!convOpt->get().isNotASwarm() && !convOpt->get().allMessagesLoaded) + if (convOpt->get().isSwarm() && !convOpt->get().allMessagesLoaded) convModel->loadConversationMessages(convOpt->get().uid, n); } diff --git a/src/qmlregister.cpp b/src/qmlregister.cpp index d8e8e0f2c326c9d7d4b2187a2cf8441bc6aa59eb..ab968a6b6cf80f366a77406d36499cf234fb6921 100644 --- a/src/qmlregister.cpp +++ b/src/qmlregister.cpp @@ -45,6 +45,7 @@ #include "api/newdevicemodel.h" #include "api/datatransfermodel.h" #include "api/pluginmodel.h" +#include "api/conversation.h" #include <QMetaType> #include <QQmlEngine> @@ -134,6 +135,7 @@ registerTypes() QML_REGISTERNAMESPACE(NS_MODELS, lrc::api::interaction::staticMetaObject, "Interaction"); QML_REGISTERNAMESPACE(NS_MODELS, lrc::api::video::staticMetaObject, "Video"); QML_REGISTERNAMESPACE(NS_MODELS, lrc::api::profile::staticMetaObject, "Profile"); + QML_REGISTERNAMESPACE(NS_MODELS, lrc::api::conversation::staticMetaObject, "Conversation"); // Same as QML_REGISTERUNCREATABLE but omit the namespace in Qml QML_REGISTERUNCREATABLE_IN_NAMESPACE(NewAccountModel, lrc::api);