Skip to content
Snippets Groups Projects
Commit fc467b58 authored by Kateryna Kostiuk's avatar Kateryna Kostiuk Committed by Sébastien Blin
Browse files

conversations: user search

Change-Id: Icc41b09d1ef72fb579f47f39b028280a58591906
parent 5f05f877
Branches
No related tags found
No related merge requests found
......@@ -75,6 +75,7 @@ public:
* @throws out_of_range exception if can't find the contact
*/
const contact::Info getContact(const QString& contactUri) const;
ContactInfoMap getSearchResults() const;
/**
* get list of banned contacts.
* @return list of banned contacts uris as string
......
......@@ -122,6 +122,26 @@ public:
* @return a copy of the conversation
*/
Q_INVOKABLE conversation::Info filteredConversation(unsigned int row) const;
/**
* Get the search results
* @return a searchResult
*/
const ConversationQueue& getAllSearchResults() const;
/**
* Get the conversation at row in the search results
* @param row
* @return a copy of the conversation
*/
conversation::Info searchResultForRow(unsigned int row) const;
/**
* Update the searchResults
* @param new status
*/
void updateSearchStatus(const QString& status) const;
/**
* Emit a filterChanged signal to force the client to refresh the filter. For instance
* this is required when a contact was banned or un-banned.
......@@ -324,6 +344,16 @@ Q_SIGNALS:
void displayedInteractionChanged(const QString& uid, const QString& participantURI,
const uint64_t previousUid, const uint64_t newdUid) const;
/**
* Emitted when search status changed
* @param status
*/
void searchStatusChanged(const QString& status) const;
/**
* Emitted when search result has been updated
*/
void searchResultUpdated() const;
private:
std::unique_ptr<ConversationModelPimpl> pimpl_;
};
......
......@@ -41,6 +41,7 @@
#include "callbackshandler.h"
#include "uri.h"
#include "vcard.h"
#include "typedefs.h"
#include "authority/daemon.h"
#include "authority/storagehelper.h"
......@@ -91,10 +92,12 @@ public:
*/
void searchRingContact(const URI& query);
void searchSipContact(const URI& query);
void jamsSearch(const URI& query);
/**
* Update temporary item to display a given message about a given uri.
*/
void updateTemporaryMessage(const QString& mes, const QString& uri);
void updateTemporaryMessage(const QString& mes);
/**
* Check if equivalent uri exist in contact
......@@ -109,7 +112,9 @@ public:
// Containers
ContactModel::ContactInfoMap contacts;
ContactModel::ContactInfoMap searchResult;
QList<QString> bannedContacts;
QString query;
std::mutex contactsMtx_;
std::mutex bannedContactsMtx_;
......@@ -189,6 +194,15 @@ public Q_SLOTS:
* @param vCard
*/
void slotProfileReceived(const QString& accountId, const QString& peer, const QString& vCard);
/**
* Listen from daemon to know when a user search completed
* @param accountId
* @param status
* @param query
* @param result
*/
void slotUserSearchEnded(const QString& accountId, int status, const QString& query, const VectorMapStringString& result);
};
using namespace authority;
......@@ -348,10 +362,12 @@ const contact::Info
ContactModel::getContact(const QString& contactUri) const
{
std::lock_guard<std::mutex> lk(pimpl_->contactsMtx_);
if (!pimpl_->contacts.contains(contactUri)) {
throw std::out_of_range("Contact out of range");
}
if (pimpl_->contacts.contains(contactUri)) {
return pimpl_->contacts.value(contactUri);
} else if (pimpl_->searchResult.contains(contactUri)) {
return pimpl_->searchResult.value(contactUri);
}
throw std::out_of_range("Contact out of range");
}
const QList<QString>&
......@@ -360,13 +376,20 @@ ContactModel::getBannedContacts() const
return pimpl_->bannedContacts;
}
ContactModel::ContactInfoMap
ContactModel::getSearchResults() const
{
return pimpl_->searchResult;
}
void
ContactModel::searchContact(const QString& query)
{
// always reset temporary contact
pimpl_->contacts[""] = {};
pimpl_->searchResult.clear();
auto uri = URI(query);
pimpl_->query = query;
auto uriScheme = uri.schemeType();
if (static_cast<int>(uriScheme) > 2 && owner.profileInfo.type == profile::Type::SIP) {
......@@ -379,20 +402,20 @@ ContactModel::searchContact(const QString& query)
if ((uriScheme == URI::SchemeType::SIP || uriScheme == URI::SchemeType::SIPS) && owner.profileInfo.type == profile::Type::SIP) {
pimpl_->searchSipContact(uri);
} else if (uriScheme == URI::SchemeType::RING && owner.profileInfo.type == profile::Type::RING) {
bool isJamsAccount = !owner.confProperties.managerUri.isEmpty();
if (isJamsAccount)
pimpl_->jamsSearch(uri);
else
pimpl_->searchRingContact(uri);
} else {
pimpl_->updateTemporaryMessage(tr("Bad URI scheme"), uri.full());
pimpl_->updateTemporaryMessage(tr("Bad URI scheme"));
}
}
void
ContactModelPimpl::updateTemporaryMessage(const QString& mes, const QString& uri)
ContactModelPimpl::updateTemporaryMessage(const QString& mes)
{
std::lock_guard<std::mutex> lk(contactsMtx_);
auto& temporaryContact = contacts[""];
temporaryContact.profileInfo.alias = mes;
temporaryContact.profileInfo.type = profile::Type::TEMPORARY;
temporaryContact.registeredName = uri;
linked.owner.conversationModel->updateSearchStatus(mes);
}
void
......@@ -402,6 +425,7 @@ ContactModelPimpl::searchRingContact(const URI& query)
if (query.isEmpty()) {
// This will remove the temporary item
emit linked.modelUpdated(uriID);
updateTemporaryMessage("");
return;
}
......@@ -412,17 +436,30 @@ ContactModelPimpl::searchRingContact(const URI& query)
return;
}
}
auto& temporaryContact = contacts[""];
auto& temporaryContact = searchResult[uriID];
temporaryContact.profileInfo.uri = uriID;
temporaryContact.profileInfo.alias = uriID;
temporaryContact.profileInfo.type = profile::Type::TEMPORARY;
emit linked.modelUpdated(uriID);
} else {
updateTemporaryMessage(tr("Searching…"), uriID);
updateTemporaryMessage(tr("Searching…"));
// Default searching
ConfigurationManager::instance().lookupName(linked.owner.id, "", uriID);
}
}
void
ContactModelPimpl::jamsSearch(const URI& query)
{
QString uriID = query.format(URI::Section::USER_INFO | URI::Section::HOSTNAME | URI::Section::PORT);
if (query.isEmpty()) {
emit linked.modelUpdated(uriID);
updateTemporaryMessage("");
return;
}
updateTemporaryMessage(tr("Searching…"));
ConfigurationManager::instance().searchUser(linked.owner.id, uriID);
}
void
......@@ -432,10 +469,11 @@ ContactModelPimpl::searchSipContact(const URI& query)
if (query.isEmpty()) {
// This will remove the temporary item
emit linked.modelUpdated(uriID);
updateTemporaryMessage("");
return;
}
auto& temporaryContact = contacts[""];
auto& temporaryContact = searchResult[query];
{
std::lock_guard<std::mutex> lk(contactsMtx_);
if (contacts.find(uriID) == contacts.end()) {
......@@ -469,6 +507,7 @@ ContactModelPimpl::ContactModelPimpl(const ContactModel& linked,
, behaviorController(behaviorController)
, callbacksHandler(callbacksHandler)
{
qRegisterMetaType<VectorMapStringString>("VectorMapStringString");
// Init contacts map
if (linked.owner.profileInfo.type == profile::Type::SIP)
fillWithSIPContacts();
......@@ -494,6 +533,8 @@ ContactModelPimpl::ContactModelPimpl(const ContactModel& linked,
this, &ContactModelPimpl::slotNewAccountTransfer);
connect(&ConfigurationManager::instance(), &ConfigurationManagerInterface::profileReceived,
this, &ContactModelPimpl::slotProfileReceived);
connect(&ConfigurationManager::instance(), &ConfigurationManagerInterface::userSearchEnded,
this, &ContactModelPimpl::slotUserSearchEnded);
}
ContactModelPimpl::~ContactModelPimpl()
......@@ -516,6 +557,8 @@ ContactModelPimpl::~ContactModelPimpl()
this, &ContactModelPimpl::slotNewAccountTransfer);
disconnect(&ConfigurationManager::instance(), &ConfigurationManagerInterface::profileReceived,
this, &ContactModelPimpl::slotProfileReceived);
disconnect(&ConfigurationManager::instance(), &ConfigurationManagerInterface::userSearchEnded,
this, &ContactModelPimpl::slotUserSearchEnded);
}
bool
......@@ -638,6 +681,14 @@ ContactModelPimpl::slotContactAdded(const QString& accountId, const QString& con
return;
}
}
//for jams account we already have profile with avatar, use it to save to vCard
bool isJamsAccount = !linked.owner.confProperties.managerUri.isEmpty();
if (isJamsAccount) {
auto result = searchResult.find(contactUri);
if (result != searchResult.end()) {
storage::createOrUpdateProfile(linked.owner.id, result->profileInfo, true);
}
}
bool isBanned = false;
......@@ -660,7 +711,6 @@ ContactModelPimpl::slotContactAdded(const QString& accountId, const QString& con
addToContacts(contactUri, linked.owner.profileInfo.type, "", false);
}
}
if (isBanned) {
// Update the smartlist
linked.owner.conversationModel->refreshFilter();
......@@ -760,43 +810,48 @@ ContactModelPimpl::slotRegisteredNameFound(const QString& accountId,
{
if (accountId != linked.owner.id) return;
auto& temporaryContact = contacts[""];
if (status == 0 /* SUCCESS */) {
std::lock_guard<std::mutex> lk(contactsMtx_);
if (contacts.find(uri) != contacts.end()) {
// update contact and remove temporary item
contacts[uri].registeredName = registeredName;
temporaryContact = {};
searchResult.clear();
} else {
if (temporaryContact.registeredName != uri && temporaryContact.registeredName != registeredName) {
if ((query != uri && query != registeredName) || query.isEmpty()) {
// we are notified that a previous lookup ended
return;
}
// update temporary item
auto& temporaryContact = searchResult[uri];
lrc::api::profile::Info profileInfo = {uri, "", "", profile::Type::TEMPORARY};
temporaryContact = {profileInfo, registeredName, false, false};
}
} else {
if (temporaryContact.registeredName != uri && temporaryContact.registeredName != registeredName) {
{
std::lock_guard<std::mutex> lk(contactsMtx_);
if (contacts.find(uri) != contacts.end()) {
// it was lookup for contact
return;
}
}
if ((query != uri && query != registeredName) || query.isEmpty()) {
// we are notified that a previous lookup ended
return;
}
switch (status) {
case 1 /* INVALID */:
updateTemporaryMessage(tr("Invalid ID"), registeredName);
updateTemporaryMessage(tr("Invalid ID"));
break;
case 2 /* NOT FOUND */:
updateTemporaryMessage(tr("Registered name not found"), registeredName);
updateTemporaryMessage(tr("Registered name not found"));
break;
case 3 /* ERROR */:
updateTemporaryMessage(tr("Couldn't lookup…"), registeredName);
updateTemporaryMessage(tr("Couldn't lookup…"));
break;
}
return;
}
updateTemporaryMessage("");
emit linked.modelUpdated(uri);
}
......@@ -1009,6 +1064,38 @@ ContactModelPimpl::slotProfileReceived(const QString& accountId, const QString&
linked.owner.contactModel->addContact(contactInfo);
}
void
ContactModelPimpl::slotUserSearchEnded(const QString& accountId, int status, const QString& query, const VectorMapStringString& result)
{
if (query != query) return;
if (accountId != linked.owner.id) return;
searchResult.clear();
switch (status) {
case 0:/* SUCCESS */
break;
case 3:/* ERROR */
updateTemporaryMessage("could not find contact matching search");
return;
default:
return;
}
updateTemporaryMessage("");
for (auto& resultInfo : result) {
if (contacts.find(resultInfo.value("jamiId")) != contacts.end()) {
continue;
}
profile::Info profileInfo;
profileInfo.uri = resultInfo.value("jamiId");
profileInfo.type = profile::Type::TEMPORARY;
profileInfo.avatar = resultInfo.value("profilePicture");
profileInfo.alias = resultInfo.value("firstName") + " " + resultInfo.value("lastName");
contact::Info contactInfo;
contactInfo.profileInfo = profileInfo;
contactInfo.registeredName = resultInfo.value("username");
searchResult.insert(profileInfo.uri, contactInfo);
}
emit linked.modelUpdated(query);
}
} // namespace lrc
......
......@@ -76,12 +76,27 @@ public:
* @return an int.
*/
int indexOf(const QString& uid) const;
/**
* return a reference to a conversation with given uid.
* @param conversation uid.
* @param searchResultIncluded if need to search in contacts and userSearch.
* @return a reference to a conversation with given uid.
*/
conversation::Info& getConversation(const QString& uid, const bool searchResultIncluded = false);
/**
* return a conversation index from conversations or -1 if no index is found.
* @param uri of the contact to search.
* @return an int.
*/
int indexOfContact(const QString& uri) const;
/**
* return a reference to a conversation with participant.
* @param participant uri.
* @param searchResultIncluded if need to search in contacts and userSearch.
* @return a reference to a conversation with participant.
*/
conversation::Info& getConversationForContact(const QString& uid, const bool searchResultIncluded = false);
/**
* Initialize conversations_ and filteredConversations_
*/
......@@ -169,6 +184,7 @@ public:
ConversationModel::ConversationQueue conversations; ///< non-filtered conversations
ConversationModel::ConversationQueue filteredConversations;
ConversationModel::ConversationQueue searchResults;
ConversationModel::ConversationQueue customFilteredConversations;
QString filter;
profile::Type typeFilter;
......@@ -504,6 +520,12 @@ ConversationModel::getConferenceableConversations(const QString& convId, const Q
return result;
}
const ConversationModel::ConversationQueue&
ConversationModel::getAllSearchResults() const
{
return pimpl_->searchResults;
}
const ConversationModel::ConversationQueue&
ConversationModel::getFilteredConversations(const profile::Type& filter, bool forceUpdate, const bool includeBanned) const
{
......@@ -529,13 +551,10 @@ ConversationModel::getFilteredConversations(const profile::Type& filter, bool fo
conversation::Info
ConversationModel::getConversationForUID(const QString& uid) const
{
auto conversationIdx = pimpl_->indexOf(uid);
if (conversationIdx == -1 || !owner.enabled) {
return {};
}
try {
return pimpl_->conversations.at(conversationIdx);
} catch (...) {
return pimpl_->getConversation(uid, true);
}
catch (const std::out_of_range& e) {
return {};
}
}
......@@ -552,14 +571,22 @@ ConversationModel::filteredConversation(const unsigned int row) const
return conversationInfo;
}
conversation::Info
ConversationModel::searchResultForRow(const unsigned int row) const
{
const auto& results = pimpl_->searchResults;
if (row >= results.size())
return conversation::Info();
return results.at(row);
}
void
ConversationModel::makePermanent(const QString& uid)
{
auto conversationIdx = pimpl_->indexOf(uid);
if (conversationIdx == -1 || !owner.enabled)
return;
try {
auto& conversation = pimpl_->getConversation(uid, true);
auto& conversation = pimpl_->conversations.at(conversationIdx);
if (conversation.participants.empty()) {
// Should not
qDebug() << "ConversationModel::addConversation can't add a conversation with no participant";
......@@ -568,23 +595,17 @@ ConversationModel::makePermanent(const QString& uid)
// Send contact request if non used
pimpl_->sendContactRequest(conversation.participants.front());
} catch (const std::out_of_range& e) {
qDebug() << "make permanent failed. conversation not found";
}
}
void
ConversationModel::selectConversation(const QString& uid) const
{
// Get conversation
auto conversationIdx = pimpl_->indexOf(uid);
if (conversationIdx == -1)
return;
if (uid.isEmpty() && owner.contactModel->getContact("").profileInfo.uri.isEmpty()) {
// if we select the temporary contact, check if its a valid contact.
return;
}
try {
auto& conversation = pimpl_->getConversation(uid, true);
auto& conversation = pimpl_->conversations.at(conversationIdx);
bool callEnded = true;
if (!conversation.callId.isEmpty()) {
try {
......@@ -634,6 +655,9 @@ ConversationModel::selectConversation(const QString& uid) const
emit pimpl_->behaviorController.showChatView(owner.id, conversation);
}
}
} catch (const std::out_of_range& e) {
qDebug() << "select conversation failed. conversation not exists";
}
}
void
......@@ -672,12 +696,8 @@ ConversationModel::deleteObsoleteHistory(int days)
void
ConversationModelPimpl::placeCall(const QString& uid, bool isAudioOnly)
{
auto conversationIdx = indexOf(uid);
if (conversationIdx == -1 || !linked.owner.enabled)
return;
auto& conversation = conversations.at(conversationIdx);
try {
auto& conversation = getConversation(uid, true);
if (conversation.participants.empty()) {
// Should not
qDebug() << "ConversationModel::placeCall can't call a conversation without participant";
......@@ -713,7 +733,7 @@ ConversationModelPimpl::placeCall(const QString& uid, bool isAudioOnly)
auto convId = uid;
auto participant = conversation.participants.front();
bool isTemporary = participant.isEmpty();
bool isTemporary = participant == convId;
auto contactInfo = linked.owner.contactModel->getContact(participant);
auto uri = contactInfo.profileInfo.uri;
......@@ -768,6 +788,9 @@ ConversationModelPimpl::placeCall(const QString& uid, bool isAudioOnly)
if (!isTemporary) {
cb(convId);
}
} catch (const std::out_of_range& e) {
qDebug() << "could not place call to not existing conversation";
}
}
void
......@@ -785,12 +808,8 @@ ConversationModel::placeCall(const QString& uid)
void
ConversationModel::sendMessage(const QString& uid, const QString& body)
{
// FIXME potential race condition between index check and at() call
auto conversationIdx = pimpl_->indexOf(uid);
if (conversationIdx == -1 || !owner.enabled)
return;
auto& conversation = pimpl_->conversations.at(conversationIdx);
try {
auto& conversation = pimpl_->getConversation(uid, true);
if (conversation.participants.empty()) {
// Should not
......@@ -799,7 +818,8 @@ ConversationModel::sendMessage(const QString& uid, const QString& body)
}
auto convId = uid;
bool isTemporary = conversation.participants.front() == "";
//for temporary contact conversation id is the same as participant uri
bool isTemporary = conversation.participants.front() == uid;
/* Make a copy of participants list: if current conversation is temporary,
it might me destroyed while we are reading it */
......@@ -910,6 +930,9 @@ ConversationModel::sendMessage(const QString& uid, const QString& body)
if (!isTemporary) {
cb(convId);
}
}catch (const std::out_of_range& e) {
qDebug() << "could not send message to not existing conversation";
}
}
void
......@@ -919,12 +942,19 @@ ConversationModel::refreshFilter()
emit filterChanged();
}
void
ConversationModel::updateSearchStatus(const QString& status) const
{
emit searchStatusChanged(status);
}
void
ConversationModel::setFilter(const QString& filter)
{
pimpl_->filter = filter;
pimpl_->dirtyConversations = {true, true};
// Will update the temporary contact in the contactModel
pimpl_->searchResults.clear();
emit searchResultUpdated();
owner.contactModel->searchContact(filter);
emit filterChanged();
}
......@@ -1503,6 +1533,10 @@ ConversationModelPimpl::slotContactAdded(const QString& contactUri)
if (indexOf(profileInfo.uri) >= 0) {
conversations.erase(conversations.begin() + indexOf(profileInfo.uri));
}
for (unsigned int i = 0; i < searchResults.size(); ++i) {
if (searchResults.at(i).uid == profileInfo.uri)
searchResults.erase(searchResults.begin() + i);
}
sortConversations();
emit linked.conversationReady(profileInfo.uri);
......@@ -1564,74 +1598,36 @@ ConversationModelPimpl::slotContactRemoved(const QString& uri)
void
ConversationModelPimpl::slotContactModelUpdated(const QString& uri, bool needsSorted)
{
// We don't create newConversationItem if we already filter on pending
conversation::Info newConversationItem;
if (!filter.isEmpty()) {
// Create a conversation with the temporary item
conversation::Info conversationInfo;
auto& temporaryContact = linked.owner.contactModel->getContact("");
conversationInfo.uid = temporaryContact.profileInfo.uri;
conversationInfo.participants.push_back("");
conversationInfo.accountId = linked.owner.id;
// if temporary contact is already present, its alias is not empty (namely "Searching ..."),
// or its registeredName is set because it was found on the nameservice.
if (not temporaryContact.profileInfo.alias.isEmpty() || not temporaryContact.registeredName.isEmpty()) {
if (!conversations.empty()) {
auto firstContactUri = conversations.front().participants.front();
//if first conversation has uri it is already a contact
// then we must add temporary item
if (not firstContactUri.isEmpty()) {
conversations.emplace_front(conversationInfo);
} else if (not conversationInfo.uid.isEmpty()) {
// If firstContactUri is empty it means that we have to update
// this element as it is the temporary.
// Only when we have found an uri.
conversations.front() = conversationInfo;
} else if (not conversations.front().uid.isEmpty()) {
//update conversation when uri not found
//but conversation have uri from previous search
conversations.front() = conversationInfo;
}
} else {
// no conversation, add temporaryItem
conversations.emplace_front(conversationInfo);
}
//presence updated
if (!needsSorted) {
try {
auto& conversation = getConversationForContact(uri, true);
dirtyConversations = {true, true};
if (needsSorted) {
emit linked.modelSorted();
} else {
emit linked.conversationUpdated(conversations.front().uid);
emit linked.conversationUpdated(conversation.uid);
} catch (std::out_of_range&) {
qDebug() << "contact updated for not existing conversation";
}
return;
}
} else {
// No filter, so we can remove the newConversationItem
if (!conversations.empty()) {
auto firstContactUri = conversations.front().participants.front();
if (firstContactUri.isEmpty() && needsSorted) {
conversations.pop_front();
dirtyConversations = {true, true};
emit linked.modelSorted();
if (filter.isEmpty()) {
if (searchResults.empty()) {
return;
}
searchResults.clear();
emit linked.searchResultUpdated();
return;
}
searchResults.clear();
auto users = linked.owner.contactModel->getSearchResults();
for (auto& user : users) {
conversation::Info conversationInfo;
conversationInfo.uid = user.profileInfo.uri;
conversationInfo.participants.push_back(user.profileInfo.uri);
conversationInfo.accountId = linked.owner.id;
searchResults.emplace_front(conversationInfo);
}
// trigger dirtyConversation in all cases to flush emptied temporary element due to filtered contact present in list
// TL:DR : avoid duplicates and empty elements
dirtyConversations = {true, true};
int index = indexOfContact(uri);
if (index != -1) {
if (!conversations.empty() && conversations.front().participants.front().isEmpty() &&
needsSorted) {
// In this case, contact is present in list, so temporary item does not longer exists
emit linked.modelSorted();
} else {
// In this case, a presence is updated
emit linked.conversationUpdated(conversations.at(index).uid);
}
}
emit linked.searchResultUpdated();
}
void
......@@ -1695,6 +1691,38 @@ ConversationModelPimpl::indexOf(const QString& uid) const
return -1;
}
conversation::Info&
ConversationModelPimpl::getConversation(const QString& uid, const bool searchResultIncluded)
{
for (unsigned int i = 0; i < conversations.size(); ++i) {
if (conversations.at(i).uid == uid) return conversations.at(i);
}
if (searchResultIncluded) {
for (unsigned int i = 0; i < searchResults.size(); ++i) {
if (searchResults.at(i).uid == uid) return searchResults.at(i);
}
}
throw std::out_of_range("Conversation out of range");
}
conversation::Info&
ConversationModelPimpl::getConversationForContact(const QString& uri, const bool searchResultIncluded)
{
for (unsigned int i = 0; i < conversations.size(); ++i) {
if (conversations.at(i).participants.front() == uri)
return conversations.at(i);
}
if (searchResultIncluded) {
for (unsigned int i = 0; i < searchResults.size(); ++i) {
if (searchResults.at(i).participants.front() == uri)
return searchResults.at(i);
}
}
throw std::out_of_range("Conversation out of range");
}
int
ConversationModelPimpl::indexOfContact(const QString& uri) const
{
......@@ -2045,12 +2073,11 @@ ConversationModel::sendFile(const QString& convUid,
const QString& path,
const QString& filename)
{
auto conversationIdx = pimpl_->indexOf(convUid);
if (conversationIdx == -1 || !owner.enabled)
return;
try {
auto& conversation = pimpl_->getConversation(convUid, true);
const auto peerUri = pimpl_->conversations[conversationIdx].participants.front();
bool isTemporary = peerUri.isEmpty();
const auto peerUri = conversation.participants.front();
bool isTemporary = peerUri == convUid;
/* It is necessary to make a copy of convUid since it may very well point to
a field in the temporary conversation, which is going to be destroyed by
......@@ -2096,6 +2123,9 @@ ConversationModel::sendFile(const QString& convUid,
} else {
cb(convUidCopy);
}
} catch (const std::out_of_range& e) {
qDebug() << "could not send file to not existing conversation";
}
}
void
......
......@@ -184,6 +184,10 @@ public:
[this](const std::string& account_id, const std::string& from, int status) {
Q_EMIT this->composingStatusChanged(QString(account_id.c_str()), QString(from.c_str()), status > 0 ? true : false);
}),
exportable_callback<ConfigurationSignal::UserSearchEnded>(
[this](const std::string& account_id, int status, const std::string& query, const std::vector<std::map<std::string, std::string>>& results) {
Q_EMIT this->userSearchEnded(QString(account_id.c_str()), status, QString(query.c_str()), convertVecMap(results));
}),
};
dataXferHandlers = {
......@@ -725,6 +729,10 @@ public Q_SLOTS: // METHODS
return DRing::setMessageDisplayed(accountId.toStdString(), contactId.toStdString(), messageId.toStdString(), status);
}
bool searchUser(const QString& accountId, const QString& query) {
return DRing::searchUser(accountId.toStdString(), query.toStdString());
}
Q_SIGNALS: // SIGNALS
void volumeChanged(const QString& device, double value);
void accountsChanged();
......@@ -758,6 +766,7 @@ Q_SIGNALS: // SIGNALS
void accountProfileReceived(const QString& accountId, const QString& displayName, const QString& userPhoto);
void debugMessageReceived(const QString& message);
void composingStatusChanged(const QString& accountId, const QString& contactId, bool isComposing);
void userSearchEnded(const QString& accountId, int status, const QString& query, VectorMapStringString results);
};
namespace org { namespace ring { namespace Ring {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment