diff options
-rw-r--r-- | Swift/Controllers/Chat/ChatsManager.cpp | 21 | ||||
-rw-r--r-- | Swift/Controllers/Chat/ChatsManager.h | 3 | ||||
-rw-r--r-- | Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp | 73 | ||||
-rw-r--r-- | Swift/Controllers/UIInterfaces/ChatListWindow.h | 36 | ||||
-rw-r--r-- | Swift/QtUI/ChatList/ChatListRecentItem.cpp | 2 | ||||
-rw-r--r-- | Swiften/Base/Algorithm.h | 8 | ||||
-rw-r--r-- | Swiften/Client/DummyStanzaChannel.h | 14 |
7 files changed, 140 insertions, 17 deletions
diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp index db3b3b7..9db343f 100644 --- a/Swift/Controllers/Chat/ChatsManager.cpp +++ b/Swift/Controllers/Chat/ChatsManager.cpp @@ -69,3 +69,3 @@ -BOOST_CLASS_VERSION(Swift::ChatListWindow::Chat, 1) +BOOST_CLASS_VERSION(Swift::ChatListWindow::Chat, 2) @@ -98,2 +98,5 @@ namespace serialization { } + if (version > 1) { + ar & chat.inviteesNames; + } } @@ -404,2 +407,8 @@ ChatListWindow::Chat ChatsManager::createChatListChatItem(const JID& jid, const chat.impromptuJIDs = participants; + + std::map<JID, std::string> participantsNames; + for (auto& i : invitees_[jid]) { + participantsNames.emplace(i, roster_->getNameForJID(i)); + } + chat.inviteesNames = participantsNames; return chat; @@ -490,3 +499,4 @@ void ChatsManager::appendRecent(const ChatListWindow::Chat& chat) { ChatListWindow::Chat mergedChat = chat; - if (oldChat && !oldChat->impromptuJIDs.empty()) { + if (oldChat) { + mergedChat.inviteesNames.insert(oldChat->inviteesNames.begin(), oldChat->inviteesNames.end()); mergedChat.impromptuJIDs.insert(oldChat->impromptuJIDs.begin(), oldChat->impromptuJIDs.end()); @@ -499,3 +509,4 @@ void ChatsManager::prependRecent(const ChatListWindow::Chat& chat) { ChatListWindow::Chat mergedChat = chat; - if (oldChat && !oldChat->impromptuJIDs.empty()) { + if (oldChat) { + mergedChat.inviteesNames.insert(oldChat->inviteesNames.begin(), oldChat->inviteesNames.end()); mergedChat.impromptuJIDs.insert(oldChat->impromptuJIDs.begin(), oldChat->impromptuJIDs.end()); @@ -592,2 +603,6 @@ void ChatsManager::handleUIEvent(std::shared_ptr<UIEvent> event) { + std::vector<JID> missingJIDsToInvite = createImpromptuMUCEvent->getJIDs(); + for (const JID& jid : missingJIDsToInvite) { + invitees_[roomJID].insert(jid); + } // join muc diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h index 593624d..6004347 100644 --- a/Swift/Controllers/Chat/ChatsManager.h +++ b/Swift/Controllers/Chat/ChatsManager.h @@ -11,2 +11,3 @@ #include <string> +#include <set> @@ -183,2 +184,4 @@ namespace Swift { VCardManager* vcardManager_; + + std::map<JID, std::set<JID>> invitees_; }; diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp index bf645d0..52537a9 100644 --- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp +++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp @@ -18,2 +18,4 @@ #include <Swiften/Base/Algorithm.h> +#include <Swiften/Base/Log.h> +#include <Swiften/Base/LogSerializers.h> #include <Swiften/Client/Client.h> @@ -54,2 +56,3 @@ #include <Swift/Controllers/Settings/DummySettingsProvider.h> +#include <Swift/Controllers/UIEvents/CreateImpromptuMUCUIEvent.h> #include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h> @@ -69,2 +72,5 @@ +#include <Swift/QtUI/QtSwiftUtil.h> +#include <Swiften/MUC/UnitTest/MockMUC.h> + using namespace Swift; @@ -139,3 +145,2 @@ class ChatsManagerTest : public CppUnit::TestFixture { - // Message correction tests @@ -147,2 +152,5 @@ class ChatsManagerTest : public CppUnit::TestFixture { + //Imptomptu test + CPPUNIT_TEST(testImpromptuChatTitle); + CPPUNIT_TEST_SUITE_END(); @@ -1505,2 +1513,65 @@ public: + void testImpromptuChatTitle() { + stanzaChannel_->uniqueIDs_ = true; + JID mucJID("795B7BBE-9099-4A0D-81BA-C816F78E275C@test.com"); + manager_->setOnline(true); + + // Open chat window to a sender. + MockChatWindow* window = new MockChatWindow(); + std::shared_ptr<IQ> infoRequest = std::dynamic_pointer_cast<IQ>(stanzaChannel_->sentStanzas[1]); + CPPUNIT_ASSERT(infoRequest); + + std::shared_ptr<IQ> infoResponse = IQ::createResult(infoRequest->getFrom(), infoRequest->getTo(), infoRequest->getID()); + + DiscoInfo info; + info.addIdentity(DiscoInfo::Identity("Shakespearean Chat Service", "conference", "text")); + info.addFeature("http://jabber.org/protocol/muc"); + infoResponse->addPayload(std::make_shared<DiscoInfo>(info)); + stanzaChannel_->onIQReceived(infoResponse); + + std::vector<JID> jids; + jids.emplace_back("foo@test.com"); + jids.emplace_back("bar@test.com"); + + mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(mucJID, uiEventStream_).Return(window); + uiEventStream_->send(std::make_shared<CreateImpromptuMUCUIEvent>(jids, mucJID, "")); + CPPUNIT_ASSERT_EQUAL(std::string("bar@test.com, foo@test.com"), manager_->getRecentChats()[0].getTitle()); + + auto mucJoinPresence = std::dynamic_pointer_cast<Presence>(stanzaChannel_->sentStanzas[2]); + CPPUNIT_ASSERT(mucJoinPresence); + + // MUC presence reply + auto mucResponse = Presence::create(); + mucResponse->setTo(jid_); + mucResponse->setFrom(mucJoinPresence->getTo()); + mucResponse->addPayload([]() { + auto mucUser = std::make_shared<MUCUserPayload>(); + mucUser->addItem(MUCItem(MUCOccupant::Member, MUCOccupant::Participant)); + mucUser->addStatusCode(MUCUserPayload::StatusCode(110)); + mucUser->addStatusCode(MUCUserPayload::StatusCode(210)); + return mucUser; + }()); + stanzaChannel_->onPresenceReceived(mucResponse); + + // Before people join the impromptu room, the title is based on names coming from Roster + CPPUNIT_ASSERT_EQUAL(std::string("bar@test.com, foo@test.com"), manager_->getRecentChats()[0].getTitle()); + + auto mucParticipantJoined = [&](const JID& jid) { + auto participantJoinedPresence = Presence::create(); + participantJoinedPresence->setTo(jid_); + participantJoinedPresence->setFrom(mucJID.withResource(jid.toString())); + auto mucUser = std::make_shared<MUCUserPayload>(); + mucUser->addItem(MUCItem(MUCOccupant::Member, MUCOccupant::Participant)); + participantJoinedPresence->addPayload(mucUser); + return participantJoinedPresence; + }; + + for (const auto& participantJID : jids) { + stanzaChannel_->onPresenceReceived(mucParticipantJoined(participantJID)); + } + + // After people joined, the title is the list of participant nicknames or names coming from Roster (if nicknames are unavailable) + CPPUNIT_ASSERT_EQUAL(std::string("bar@test.com, foo@test.com"), manager_->getRecentChats()[0].getTitle()); + } + diff --git a/Swift/Controllers/UIInterfaces/ChatListWindow.h b/Swift/Controllers/UIInterfaces/ChatListWindow.h index dde596e..29097e9 100644 --- a/Swift/Controllers/UIInterfaces/ChatListWindow.h +++ b/Swift/Controllers/UIInterfaces/ChatListWindow.h @@ -13,2 +13,4 @@ + +#include <boost/algorithm/string/join.hpp> #include <boost/filesystem/path.hpp> @@ -16,2 +18,3 @@ +#include <Swiften/Base/Algorithm.h> #include <Swiften/Elements/StatusShow.h> @@ -33,2 +36,5 @@ namespace Swift { } + if (chatName == other.chatName) { + return true; + } else { /* compare the chat occupant lists */ @@ -46,3 +52,3 @@ namespace Swift { } - return true; + return key_compare(inviteesNames, other.inviteesNames); } @@ -59,11 +65,24 @@ namespace Swift { std::string getImpromptuTitle() const { - std::string title; - for (auto& pair : impromptuJIDs) { - if (title.empty()) { - title += pair.first; - } else { - title += ", " + pair.first; + std::set<std::string> participants; + std::map<JID, std::string> participantsMap; + + for (auto& pair : inviteesNames) { + if (!pair.second.empty()) { + participantsMap[pair.first] = pair.second; } + else { + participantsMap[pair.first] = pair.first.toString(); + } + } + for (auto& pair : impromptuJIDs) { + participantsMap[pair.second] = pair.first; } - return title; + for (auto& participant : participantsMap) { + participants.insert(participant.second); + } + return boost::algorithm::join(participants, ", "); + } + std::string getTitle() const { + std::string title = getImpromptuTitle(); + return title.empty() ? chatName : title; } @@ -79,2 +98,3 @@ namespace Swift { std::map<std::string, JID> impromptuJIDs; + std::map<JID, std::string> inviteesNames; bool isPrivateMessage; diff --git a/Swift/QtUI/ChatList/ChatListRecentItem.cpp b/Swift/QtUI/ChatList/ChatListRecentItem.cpp index faac937..9e55e1b 100644 --- a/Swift/QtUI/ChatList/ChatListRecentItem.cpp +++ b/Swift/QtUI/ChatList/ChatListRecentItem.cpp @@ -24,3 +24,3 @@ QVariant ChatListRecentItem::data(int role) const { switch (role) { - case Qt::DisplayRole: return chat_.impromptuJIDs.empty() ? P2QSTRING(chat_.chatName) : P2QSTRING(chat_.getImpromptuTitle()); + case Qt::DisplayRole: return P2QSTRING(chat_.getTitle()); case DetailTextRole: return P2QSTRING(chat_.activity); diff --git a/Swiften/Base/Algorithm.h b/Swiften/Base/Algorithm.h index c481aa8..108dbe3 100644 --- a/Swiften/Base/Algorithm.h +++ b/Swiften/Base/Algorithm.h @@ -154,2 +154,10 @@ namespace Swift { }; + + template <typename Map> + bool key_compare(Map const& lhs, Map const& rhs) { + + auto pred = [](decltype(*lhs.begin()) a, decltype(a) b) { return a.first == b.first; }; + + return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin(), pred); + } } diff --git a/Swiften/Client/DummyStanzaChannel.h b/Swiften/Client/DummyStanzaChannel.h index fc2f05b..4cc0f7e 100644 --- a/Swiften/Client/DummyStanzaChannel.h +++ b/Swiften/Client/DummyStanzaChannel.h @@ -1,3 +1,3 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2017 Isode Limited. * All rights reserved. @@ -15,3 +15,3 @@ namespace Swift { public: - DummyStanzaChannel() : available_(true) {} + DummyStanzaChannel() {} @@ -39,3 +39,7 @@ namespace Swift { virtual std::string getNewIQID() { - return "test-id"; + std::string id = "test-id"; + if (uniqueIDs_) { + id += "-" + std::to_string(idCounter_++); + } + return id; } @@ -96,3 +100,5 @@ namespace Swift { std::vector<std::shared_ptr<Stanza> > sentStanzas; - bool available_; + bool available_ = true; + bool uniqueIDs_ = false; + unsigned int idCounter_ = 0; }; |