diff --git a/src/api/conversation.h b/src/api/conversation.h index 9bddff558d911025b9184b54cabaf890d6705475..fe828bf5f2029407c370245bab1886b71e596d65 100644 --- a/src/api/conversation.h +++ b/src/api/conversation.h @@ -37,18 +37,18 @@ static inline Mode to_mode(const int intMode) { switch (intMode) { - case 0: - return Mode::ONE_TO_ONE; - case 1: - return Mode::ADMIN_INVITES_ONLY; - case 2: - return Mode::INVITES_ONLY; - case 3: - return Mode::PUBLIC; - case 4: - return Mode::NON_SWARM; - default: - return Mode::ONE_TO_ONE; + case 0: + return Mode::ONE_TO_ONE; + case 1: + return Mode::ADMIN_INVITES_ONLY; + case 2: + return Mode::INVITES_ONLY; + case 3: + return Mode::PUBLIC; + case 4: + return Mode::NON_SWARM; + default: + return Mode::ONE_TO_ONE; } } @@ -75,6 +75,7 @@ struct Info QString getCallId() { return confId.isEmpty() ? callId : confId; } Mode mode = Mode::NON_SWARM; + bool needsSyncing = false; bool isRequest = false; }; diff --git a/src/chatview.cpp b/src/chatview.cpp index b673233f2211ffbdad9b30af9d688eca2e4ae5ca..57f3d5abe07f13093bc7ef7bb683c32526e076e9 100644 --- a/src/chatview.cpp +++ b/src/chatview.cpp @@ -49,6 +49,10 @@ getTranslatedStrings(bool qwebview) QObject::tr("has sent you a conversation request.")}, {"Hello, do you want to join the conversation?", QObject::tr("Hello, do you want to join the conversation?")}, + {"You have accepted the conversation request.", + QObject::tr("You have accepted the conversation request.")}, + {"We are waiting for another device to synchronize the conversation.", + QObject::tr("We are waiting for another device to synchronize the conversation.")}, {"Note: you can automatically accept this invitation by sending a message.", QObject::tr("Note: you can automatically accept this invitation by sending a message.")}, {"%d days ago", qwebview ? QObject::tr("{0} days ago") : QObject::tr("%d days ago")}, diff --git a/src/contactmodel.cpp b/src/contactmodel.cpp index 2b2ffb1a48e0ed5c9e6f42300135550e69fb855c..341dfb6f0e96fa06a3a1f0feb12dc40dcb7df700 100644 --- a/src/contactmodel.cpp +++ b/src/contactmodel.cpp @@ -84,11 +84,13 @@ public: * @param type * @param displayName * @param banned whether contact is banned or not + * @param conversationId linked swarm if one */ void addToContacts(const QString& contactId, const profile::Type& type, const QString& displayName = "", - bool banned = false); + bool banned = false, + const QString& conversationId = ""); /** * Helpers for searchContact. Search for a given classic or SIP contact. */ @@ -662,7 +664,11 @@ ContactModelPimpl::fillWithJamiContacts() for (auto contact_info : contacts_vector) { std::lock_guard<std::mutex> lk(contactsMtx_); bool banned = contact_info["banned"] == "true" ? true : false; - addToContacts(contact_info["id"], linked.owner.profileInfo.type, "", banned); + addToContacts(contact_info["id"], + linked.owner.profileInfo.type, + "", + banned, + contact_info["conversationId"]); } // Add pending contacts @@ -692,6 +698,7 @@ ContactModelPimpl::fillWithJamiContacts() contactInfo.profileInfo.avatar = photo.constData(); contactInfo.registeredName = ""; contactInfo.isBanned = false; + contactInfo.conversationId = tr_info[DRing::Account::TrustRequest::CONVERSATIONID]; { std::lock_guard<std::mutex> lk(contactsMtx_); @@ -792,7 +799,13 @@ ContactModelPimpl::slotContactAdded(const QString& accountId, bannedContacts.erase(it); } - addToContacts(contactUri, linked.owner.profileInfo.type, "", false); + MapStringString details = ConfigurationManager::instance() + .getContactDetails(linked.owner.id, contactUri); + addToContacts(contactUri, + linked.owner.profileInfo.type, + "", + false, + details["conversationId"]); } } if (isBanned) { @@ -864,7 +877,8 @@ void ContactModelPimpl::addToContacts(const QString& contactUri, const profile::Type& type, const QString& displayName, - bool banned) + bool banned, + const QString& conversationId) { // create a vcard if necessary profile::Info profileInfo {contactUri, {}, displayName, linked.owner.profileInfo.type}; @@ -872,6 +886,7 @@ ContactModelPimpl::addToContacts(const QString& contactUri, auto contactInfo = storage::buildContactFromProfile(linked.owner.id, contactUri, type); contactInfo.isBanned = banned; + contactInfo.conversationId = conversationId; // lookup address in case of RING contact if (type == profile::Type::JAMI) { diff --git a/src/conversationmodel.cpp b/src/conversationmodel.cpp index b9a0070da869f29e3295bdf204d69fa356655f9d..0738adeb5cb3d0bb341014498ccd596f149b6844 100644 --- a/src/conversationmodel.cpp +++ b/src/conversationmodel.cpp @@ -1485,6 +1485,9 @@ ConversationModel::acceptConversationRequest(const QString& conversationId) default: break; } + conversation.needsSyncing = true; + pimpl_->invalidateModel(); + emit modelChanged(); ConfigurationManager::instance().acceptConversationRequest(owner.id, conversationId); } @@ -1843,6 +1846,16 @@ ConversationModelPimpl::initConversations() conv.push_back(storage::beginConversationWithPeer(db, c.second.profileInfo.uri)); } addConversationWith(conv[0], c.first); + if (!c.second.conversationId.isEmpty()) { + // it is a swarm conversation. + try { + auto& conversation = getConversationForUid(conv[0]).get(); + conversation.mode = conversation::Mode::ONE_TO_ONE; + conversation.needsSyncing = true; + } catch (...) { + continue; + } + } auto convIdx = indexOf(conv[0]); @@ -2278,6 +2291,7 @@ ConversationModelPimpl::slotConversationReady(const QString& accountId, .conversationInfos(accountId, conversationId); conversation.mode = conversation::to_mode(details["mode"].toInt()); conversation.isRequest = false; + conversation.needsSyncing = false; auto id = ConfigurationManager::instance().loadConversationMessages(linked.owner.id, conversationId, "", @@ -2402,6 +2416,13 @@ ConversationModelPimpl::slotContactAdded(const QString& contactUri) auto& conversation = getConversationForPeerUri(contactUri).get(); // swarm conversation we update when receive conversation ready signal. if (conversation.mode != conversation::Mode::NON_SWARM) { + QStringList swarms = ConfigurationManager::instance().getConversations(linked.owner.id); + bool needsSyncing = swarms.indexOf(conversation.uid) == -1; + if (conversation.needsSyncing != needsSyncing) { + conversation.needsSyncing = needsSyncing; + invalidateModel(); + emit linked.modelChanged(); + } return; } if (conv.empty()) { @@ -2623,6 +2644,7 @@ ConversationModelPimpl::addSwarmConversation(const QString& convId) } catch (...) { } } + conversation.needsSyncing = false; conversations.emplace_back(std::move(conversation)); auto id = ConfigurationManager::instance().loadConversationMessages(linked.owner.id, convId, @@ -2638,6 +2660,7 @@ ConversationModelPimpl::addConversationWith(const QString& convId, const QString conversation.accountId = linked.owner.id; conversation.participants = {contactUri}; conversation.mode = conversation::Mode::NON_SWARM; + conversation.needsSyncing = false; try { conversation.confId = linked.owner.callModel->getConferenceFromURI(contactUri).id; } catch (...) { diff --git a/src/web-chatview/chatview.css b/src/web-chatview/chatview.css index e362134e6e16b06ed1e0803e481b2e7d06f03c11..13fadb78fe35da63703fff5eea511ba889c1710a 100644 --- a/src/web-chatview/chatview.css +++ b/src/web-chatview/chatview.css @@ -1139,7 +1139,11 @@ video { } #join_text { - font-size: 18px; + font-size: 1.1em; + } + + #note_text { + font-size: .8em; } } @@ -1164,7 +1168,11 @@ video { } #join_text { - font-size: 16px; + font-size: 1em; + } + + #note_text { + font-size: .8em; } } diff --git a/src/web-chatview/chatview.html b/src/web-chatview/chatview.html index ed277b7cc74037074959741b958f0cfdd43570a8..1d89434d85c5acb31c6a90da536668a0a8cf27ec 100644 --- a/src/web-chatview/chatview.html +++ b/src/web-chatview/chatview.html @@ -121,7 +121,8 @@ <div id="typing_indicator_container"></div> <div id="back_to_bottom_button_container"> - <div id="back_to_bottom_button" onclick="back_to_bottom()">Jump to latest ▼</div> + <div id="back_to_bottom_button" onclick="back_to_bottom()">Jump to latest ▼ +</div> </div> <div id="send_inteface_container" onresize="updateBackToBottomContainer()"> <div id="sendMessage"> diff --git a/src/web-chatview/chatview.js b/src/web-chatview/chatview.js index 34d74a45766bd9da05f6f0cc1d507c8263ed5ec3..311d50a79b58494adb6132dd1dff507a52b80e13 100644 --- a/src/web-chatview/chatview.js +++ b/src/web-chatview/chatview.js @@ -64,6 +64,7 @@ const navbar = document.getElementById("navbar") const emojiBtn = document.getElementById('emojiButton'); const invitationText = document.getElementById("invitation_text") const joinText = document.getElementById("join_text") +const noteText = document.getElementById("note_text") const invitationNoteText = document.getElementById("invitation_note") var messages = document.getElementById("messages") @@ -379,9 +380,11 @@ function update_chatview_frame(accountEnabled, banned, temporary, alias, bestid) * * @param contactAlias * @param contactId + * @param isSwarm + * @param isSyncing */ /* exported showInvitation */ -function showInvitation(contactAlias, contactId, isSwarm) { +function showInvitation(contactAlias, contactId, isSwarm, isSyncing) { if (!contactAlias) { if (hasInvitation) { hasInvitation = false @@ -408,9 +411,17 @@ function showInvitation(contactAlias, contactId, isSwarm) { i18n.sprintf(i18n.gettext("%s has sent you a conversation request."), contactAlias)) + "<br/>" + var joinTextValue = (isSyncing ? + "You have accepted the conversation request." : + "Hello, do you want to join the conversation?") joinText.innerHTML = (use_qt ? - i18nStringData["Hello, do you want to join the conversation?"] : - i18n.gettext("Hello, do you want to join the conversation?")) + i18nStringData[joinTextValue] : + i18n.gettext(joinTextValue)) + + "<br/>" + + noteText.innerHTML = (use_qt ? + i18nStringData["We are waiting for another device to synchronize the conversation."] : + i18n.gettext("We are waiting for another device to synchronize the conversation.")) + "<br/>" invitationNoteText.innerHTML = (use_qt ? @@ -428,7 +439,7 @@ function showInvitation(contactAlias, contactId, isSwarm) { invitationNoteText.style.visibility = "visible" messageBar.style.visibility = "visible" } - + invitation.style.display = "flex" invitation.style.visibility = "visible" @@ -1022,14 +1033,7 @@ function fileInteraction(message_id, message_direction) { const internal_mes_wrapper = document.createElement("div") internal_mes_wrapper.setAttribute("class", "internal_mes_wrapper") - // if(use_qt) { - // var tbl = buildMsgTable(message_direction) - // var msg_cell = tbl.querySelector(".msg_cell") - // msg_cell.appendChild(message_wrapper) - // internal_mes_wrapper.appendChild(tbl) - // } else { - internal_mes_wrapper.appendChild(message_wrapper) - // } + internal_mes_wrapper.appendChild(message_wrapper) return internal_mes_wrapper }