From 324200dfd7d70324fe15329100140d98bb1f9b17 Mon Sep 17 00:00:00 2001 From: Seth ProductEngine Date: Thu, 9 Aug 2012 00:00:25 +0300 Subject: CHUI-120 WIP Added notifications about newly invited chat participants. --- indra/newview/llimfloater.cpp | 124 ++++++++++++++++----- indra/newview/llimfloater.h | 3 +- .../skins/default/xui/en/floater_im_session.xml | 6 + .../newview/skins/default/xui/en/notifications.xml | 14 +++ 4 files changed, 120 insertions(+), 27 deletions(-) diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index 3399a88c9e..a2989375ea 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -352,19 +352,19 @@ BOOL LLIMFloater::postBuild() } void LLIMFloater::onAddButtonClicked() +{ + LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(boost::bind(&LLIMFloater::onAddSessionParticipants, this, _1), TRUE, TRUE); + if (!picker) { - LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(boost::bind(&LLIMFloater::addSessionParticipants, this, _1), TRUE, TRUE); - if (!picker) - { - return; + return; } - // Need to disable 'ok' button when selected users are already in conversation. - picker->setOkBtnEnableCb(boost::bind(&LLIMFloater::canAddSelectedToChat, this, _1)); - LLFloater* root_floater = gFloaterView->getParentFloater(this); - if (root_floater) + // Need to disable 'ok' button when selected users are already in conversation. + picker->setOkBtnEnableCb(boost::bind(&LLIMFloater::canAddSelectedToChat, this, _1)); + LLFloater* root_floater = gFloaterView->getParentFloater(this); + if (root_floater) { - root_floater->addDependentFloater(picker); + root_floater->addDependentFloater(picker); } } @@ -420,8 +420,54 @@ bool LLIMFloater::canAddSelectedToChat(const uuid_vec_t& uuids) return true; } -void LLIMFloater::addSessionParticipants(const uuid_vec_t& uuids) +void LLIMFloater::onAddSessionParticipants(const uuid_vec_t& uuids) +{ + LLSD payload; + LLSD args; + for (uuid_vec_t::const_iterator iter = uuids.begin(); iter != uuids.end(); ++iter) + { + payload["participant_ids"].append(*iter); + } + + LLNotificationsUtil::add("ConfirmAddingChatParticipants", args, payload, + boost::bind(&LLIMFloater::addSessionParticipants, this, _1, _2)); +} + +void LLIMFloater::addSessionParticipants(const LLSD& notification, const LLSD& response) +{ + uuid_vec_t uuids; + LLSD::array_const_iterator list_it = notification["payload"]["participant_ids"].beginArray(); + LLSD::array_const_iterator list_end = notification["payload"]["participant_ids"].endArray(); + for (; list_it != list_end; ++list_it) + { + uuids.push_back(list_it->asUUID()); + } + + std::vector avatar_names; + uuid_vec_t::const_iterator it = uuids.begin(); + for (; it != uuids.end(); ++it) { + const LLUUID& id = *it; + LLAvatarName av_name; + if (LLAvatarNameCache::get(id, &av_name)) + { + avatar_names.push_back(av_name); + } + } + + std::string added_participants; + + // We should check whether the vector is not empty to pass the assertion + // that avatar_names.size() > 0 in LLAvatarActions::buildResidentsString. + if (!avatar_names.empty()) + { + LLAvatarActions::buildResidentsString(avatar_names, added_participants); + } + + LLStringUtil::format_map_t args; + args["[NAMES]"] = added_participants; + std::string participants_added_notification; + if (mIsP2PChat) { mStartConferenceInSameFloater = true; @@ -440,19 +486,45 @@ void LLIMFloater::addSessionParticipants(const uuid_vec_t& uuids) // then we can close the current session onClose(false); + participants_added_notification = getString("participants_added_new_window", args); + participants_added_notification = utf8str_truncate(participants_added_notification, MAX_MSG_BUF_SIZE - 1); + + if (mSessionInitialized) + { + LLIMModel::sendMessage(participants_added_notification, mSessionID, mOtherParticipantUUID, mDialog); + } + else + { + //queue up the message to send once the session is initialized + mQueuedMsgsForInit.append(participants_added_notification); + } + // Start a new ad hoc voice call if we invite new participants to a P2P call, // or start a text chat otherwise. if (is_voice_call) { LLAvatarActions::startAdhocCall(temp_ids, mSessionID); - } - else - { + } + else + { LLAvatarActions::startConference(temp_ids, mSessionID); + } } -} else { + participants_added_notification = getString("participants_added", args); + participants_added_notification = utf8str_truncate(participants_added_notification, MAX_MSG_BUF_SIZE - 1); + + if (mSessionInitialized) + { + LLIMModel::sendMessage(participants_added_notification, mSessionID, mOtherParticipantUUID, mDialog); + } + else + { + //queue up the message to send once the session is initialized + mQueuedMsgsForInit.append(participants_added_notification); + } + inviteToSession(uuids); } } @@ -1115,19 +1187,19 @@ BOOL LLIMFloater::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, if (cargo_type == DAD_PERSON) { if (dropPerson(static_cast(cargo_data), drop)) - { + { *accept = ACCEPT_YES_MULTI; - } + } else - { - *accept = ACCEPT_NO; - } + { + *accept = ACCEPT_NO; } + } else if (mDialog == IM_NOTHING_SPECIAL) - { + { LLToolDragAndDrop::handleGiveDragAndDrop(mOtherParticipantUUID, mSessionID, drop, cargo_type, cargo_data, accept); - } + } return TRUE; } @@ -1137,18 +1209,18 @@ bool LLIMFloater::dropPerson(LLUUID* person_id, bool drop) bool res = person_id && person_id->notNull(); if(res) { - uuid_vec_t ids; + uuid_vec_t ids; ids.push_back(*person_id); res = canAddSelectedToChat(ids); if(res && drop) - { - addSessionParticipants(ids); + { + onAddSessionParticipants(ids); + } } -} return res; - } +} BOOL LLIMFloater::isInviteAllowed() const { diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h index 434613ff43..d98213b54c 100644 --- a/indra/newview/llimfloater.h +++ b/indra/newview/llimfloater.h @@ -160,7 +160,8 @@ private: static void onInputEditorKeystroke(LLTextEditor* caller, void* userdata); void setTyping(bool typing); void onAddButtonClicked(); - void addSessionParticipants(const uuid_vec_t& uuids); + void onAddSessionParticipants(const uuid_vec_t& uuids); + void addSessionParticipants(const LLSD& notification, const LLSD& response); bool canAddSelectedToChat(const uuid_vec_t& uuids); void onCallButtonClicked(); diff --git a/indra/newview/skins/default/xui/en/floater_im_session.xml b/indra/newview/skins/default/xui/en/floater_im_session.xml index 4abe4d6941..2b63430106 100644 --- a/indra/newview/skins/default/xui/en/floater_im_session.xml +++ b/indra/newview/skins/default/xui/en/floater_im_session.xml @@ -34,6 +34,12 @@ + + + + +When you add a person to an existing conversation, a new conversation will be created. All participants will receive new conversation notifications. + confirm + + + Date: Fri, 10 Aug 2012 02:51:56 +0300 Subject: CHUI-120 WIP Different notifications about single and multiple chat participants invited. The notification about starting a new conversation now applies only to P2P chat. Some code refactoring and clean up. --- indra/newview/llimfloater.cpp | 285 +++++++++------------ indra/newview/llimfloater.h | 8 +- .../skins/default/xui/en/floater_im_session.xml | 11 +- 3 files changed, 137 insertions(+), 167 deletions(-) diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index a2989375ea..c3c9e334f2 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -60,6 +60,10 @@ #include "llnotificationmanager.h" #include "llautoreplace.h" +/// Helper function to resolve resident names from given uuids +/// and form a string of names separated by "words_separator". +static void build_names_string(const uuid_vec_t& uuids, std::string& names_string); + floater_showed_signal_t LLIMFloater::sIMFloaterShowedSignal; LLIMFloater::LLIMFloater(const LLUUID& session_id) @@ -186,49 +190,55 @@ void LLIMFloater::onVisibilityChange(const LLSD& new_visibility) void LLIMFloater::onSendMsg( LLUICtrl* ctrl, void* userdata ) { LLIMFloater* self = (LLIMFloater*) userdata; - self->sendMsg(); + self->sendMsgFromInputEditor(); self->setTyping(false); } -void LLIMFloater::sendMsg() +void LLIMFloater::sendMsgFromInputEditor() { if (gAgent.isGodlike() || (mDialog != IM_NOTHING_SPECIAL) || !mOtherParticipantUUID.isNull()) { - if (mInputEditor) - { + if (mInputEditor) + { LLWString text = mInputEditor->getWText(); LLWStringUtil::trim(text); LLWStringUtil::replaceChar(text,182,'\n'); // Convert paragraph symbols back into newlines. - if(!text.empty()) - { - // Truncate and convert to UTF8 for transport - std::string utf8_text = wstring_to_utf8str(text); - utf8_text = utf8str_truncate(utf8_text, MAX_MSG_BUF_SIZE - 1); - - if (mSessionInitialized) - { - LLIMModel::sendMessage(utf8_text, mSessionID, mOtherParticipantUUID, mDialog); - } - else + if(!text.empty()) { - //queue up the message to send once the session is initialized - mQueuedMsgsForInit.append(utf8_text); - } + // Truncate and convert to UTF8 for transport + std::string utf8_text = wstring_to_utf8str(text); - mInputEditor->setText(LLStringUtil::null); + sendMsg(utf8_text); - updateMessages(); + mInputEditor->setText(LLStringUtil::null); + } } } -} else { llinfos << "Cannot send IM to everyone unless you're a god." << llendl; } } +void LLIMFloater::sendMsg(const std::string& msg) +{ + const std::string utf8_text = utf8str_truncate(msg, MAX_MSG_BUF_SIZE - 1); + + if (mSessionInitialized) + { + LLIMModel::sendMessage(utf8_text, mSessionID, mOtherParticipantUUID, mDialog); + } + else + { + //queue up the message to send once the session is initialized + mQueuedMsgsForInit.append(utf8_text); + } + + updateMessages(); +} + LLIMFloater::~LLIMFloater() { mParticipantsListRefreshConnection.disconnect(); @@ -241,6 +251,7 @@ LLIMFloater::~LLIMFloater() LLTransientFloaterMgr::getInstance()->removeControlView(LLTransientFloaterMgr::IM, this); } + void LLIMFloater::initIMSession(const LLUUID& session_id) { // Change the floater key to bind it to a new session. @@ -353,7 +364,7 @@ BOOL LLIMFloater::postBuild() void LLIMFloater::onAddButtonClicked() { - LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(boost::bind(&LLIMFloater::onAddSessionParticipants, this, _1), TRUE, TRUE); + LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(boost::bind(&LLIMFloater::addSessionParticipants, this, _1), TRUE, TRUE); if (!picker) { return; @@ -420,113 +431,65 @@ bool LLIMFloater::canAddSelectedToChat(const uuid_vec_t& uuids) return true; } -void LLIMFloater::onAddSessionParticipants(const uuid_vec_t& uuids) +void LLIMFloater::addSessionParticipants(const uuid_vec_t& uuids) { - LLSD payload; - LLSD args; - for (uuid_vec_t::const_iterator iter = uuids.begin(); iter != uuids.end(); ++iter) + if (mIsP2PChat) { - payload["participant_ids"].append(*iter); - } - - LLNotificationsUtil::add("ConfirmAddingChatParticipants", args, payload, - boost::bind(&LLIMFloater::addSessionParticipants, this, _1, _2)); -} + LLSD payload; + LLSD args; -void LLIMFloater::addSessionParticipants(const LLSD& notification, const LLSD& response) -{ - uuid_vec_t uuids; - LLSD::array_const_iterator list_it = notification["payload"]["participant_ids"].beginArray(); - LLSD::array_const_iterator list_end = notification["payload"]["participant_ids"].endArray(); - for (; list_it != list_end; ++list_it) - { - uuids.push_back(list_it->asUUID()); + LLNotificationsUtil::add("ConfirmAddingChatParticipants", args, payload, + boost::bind(&LLIMFloater::addP2PSessionParticipants, this, uuids)); } - - std::vector avatar_names; - uuid_vec_t::const_iterator it = uuids.begin(); - for (; it != uuids.end(); ++it) + else { - const LLUUID& id = *it; - LLAvatarName av_name; - if (LLAvatarNameCache::get(id, &av_name)) - { - avatar_names.push_back(av_name); - } - } - - std::string added_participants; + sendParticipantsAddedNotification(uuids); - // We should check whether the vector is not empty to pass the assertion - // that avatar_names.size() > 0 in LLAvatarActions::buildResidentsString. - if (!avatar_names.empty()) - { - LLAvatarActions::buildResidentsString(avatar_names, added_participants); + inviteToSession(uuids); } +} - LLStringUtil::format_map_t args; - args["[NAMES]"] = added_participants; - std::string participants_added_notification; - - if (mIsP2PChat) - { - mStartConferenceInSameFloater = true; +void LLIMFloater::addP2PSessionParticipants(const uuid_vec_t& uuids) +{ + sendParticipantsAddedNotification(uuids); - uuid_vec_t temp_ids; + mStartConferenceInSameFloater = true; - // Add the initial participant of a P2P session - temp_ids.push_back(mOtherParticipantUUID); - temp_ids.insert(temp_ids.end(), uuids.begin(), uuids.end()); + LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionID); - LLVoiceChannel* voice_channel = LLIMModel::getInstance()->getVoiceChannel(mSessionID); + // first check whether this is a voice session + bool is_voice_call = voice_channel != NULL && voice_channel->isActive(); - // first check whether this is a voice session - bool is_voice_call = voice_channel != NULL && voice_channel->isActive(); + uuid_vec_t temp_ids; - // then we can close the current session - onClose(false); + // Add the initial participant of a P2P session + temp_ids.push_back(mOtherParticipantUUID); + temp_ids.insert(temp_ids.end(), uuids.begin(), uuids.end()); - participants_added_notification = getString("participants_added_new_window", args); - participants_added_notification = utf8str_truncate(participants_added_notification, MAX_MSG_BUF_SIZE - 1); + // then we can close the current session + onClose(false); - if (mSessionInitialized) - { - LLIMModel::sendMessage(participants_added_notification, mSessionID, mOtherParticipantUUID, mDialog); - } - else - { - //queue up the message to send once the session is initialized - mQueuedMsgsForInit.append(participants_added_notification); - } - - // Start a new ad hoc voice call if we invite new participants to a P2P call, - // or start a text chat otherwise. - if (is_voice_call) - { - LLAvatarActions::startAdhocCall(temp_ids, mSessionID); - } - else - { - LLAvatarActions::startConference(temp_ids, mSessionID); - } + // Start a new ad hoc voice call if we invite new participants to a P2P call, + // or start a text chat otherwise. + if (is_voice_call) + { + LLAvatarActions::startAdhocCall(temp_ids, mSessionID); } else { - participants_added_notification = getString("participants_added", args); - participants_added_notification = utf8str_truncate(participants_added_notification, MAX_MSG_BUF_SIZE - 1); + LLAvatarActions::startConference(temp_ids, mSessionID); + } +} - if (mSessionInitialized) - { - LLIMModel::sendMessage(participants_added_notification, mSessionID, mOtherParticipantUUID, mDialog); - } - else - { - //queue up the message to send once the session is initialized - mQueuedMsgsForInit.append(participants_added_notification); - } +void LLIMFloater::sendParticipantsAddedNotification(const uuid_vec_t& uuids) +{ + std::string names_string; + build_names_string(uuids, names_string); + LLStringUtil::format_map_t args; + args["[NAME]"] = names_string; + args["[NEW_WINDOW]"] = mIsP2PChat ? getString("new_window") : LLStringUtil::null; - inviteToSession(uuids); - } + sendMsg(getString(uuids.size() > 1 ? "multiple_participants_added" : "participant_added", args)); } void LLIMFloater::boundVoiceChannel() @@ -619,17 +582,19 @@ void LLIMFloater::onParticipantsListChanged(LLUICtrl* ctrl) if (!avatar_list) { return; - } + } bool all_names_resolved = true; std::vector participants_uuids; + uuid_vec_t temp_uuids; // uuids vector for building the added participants' names string avatar_list->getValues(participants_uuids); // Check whether we have all participants names in LLAvatarNameCache for (std::vector::const_iterator it = participants_uuids.begin(); it != participants_uuids.end(); ++it) -{ + { const LLUUID& id = it->asUUID(); + temp_uuids.push_back(id); LLAvatarName av_name; if (!LLAvatarNameCache::get(id, &av_name)) { @@ -641,31 +606,14 @@ void LLIMFloater::onParticipantsListChanged(LLUICtrl* ctrl) boost::bind(&LLIMFloater::onParticipantsListChanged, this, avatar_list)); break; } -} + } if (all_names_resolved) { - std::vector avatar_names; - std::vector::const_iterator it = participants_uuids.begin(); - for (; it != participants_uuids.end(); ++it) - { - const LLUUID& id = it->asUUID(); - LLAvatarName av_name; - if (LLAvatarNameCache::get(id, &av_name)) -{ - avatar_names.push_back(av_name); - } -} - - // We should check whether the vector is not empty to pass the assertion - // that avatar_names.size() > 0 in LLAvatarActions::buildResidentsString. - if (!avatar_names.empty()) -{ - std::string ui_title; - LLAvatarActions::buildResidentsString(avatar_names, ui_title); - updateSessionName(ui_title, ui_title); - } -} + std::string ui_title; + build_names_string(temp_uuids, ui_title); + updateSessionName(ui_title, ui_title); + } } //static @@ -1215,7 +1163,7 @@ bool LLIMFloater::dropPerson(LLUUID* person_id, bool drop) res = canAddSelectedToChat(ids); if(res && drop) { - onAddSessionParticipants(ids); + addSessionParticipants(ids); } } @@ -1254,37 +1202,32 @@ BOOL LLIMFloater::inviteToSession(const uuid_vec_t& ids) if (is_region_exist) { - S32 count = ids.size(); + S32 count = ids.size(); - if( isInviteAllowed() && (count > 0) ) - { - llinfos << "LLIMFloater::inviteToSession() - inviting participants" << llendl; - - std::string url = region->getCapability("ChatSessionRequest"); + if( isInviteAllowed() && (count > 0) ) + { + llinfos << "LLIMFloater::inviteToSession() - inviting participants" << llendl; - LLSD data; + std::string url = region->getCapability("ChatSessionRequest"); - data["params"] = LLSD::emptyArray(); - for (int i = 0; i < count; i++) + LLSD data; + data["params"] = LLSD::emptyArray(); + for (int i = 0; i < count; i++) + { + data["params"].append(ids[i]); + } + data["method"] = "invite"; + data["session-id"] = mSessionID; + LLHTTPClient::post(url, data,new LLSessionInviteResponder(mSessionID)); + } + else { - data["params"].append(ids[i]); + llinfos << "LLIMFloater::inviteToSession -" + << " no need to invite agents for " + << mDialog << llendl; + // successful add, because everyone that needed to get added + // was added. } - - data["method"] = "invite"; - data["session-id"] = mSessionID; - LLHTTPClient::post( - url, - data, - new LLSessionInviteResponder(mSessionID)); - } - else - { - llinfos << "LLIMFloater::inviteToSession -" - << " no need to invite agents for " - << mDialog << llendl; - // successful add, because everyone that needed to get added - // was added. - } } return is_region_exist; @@ -1414,3 +1357,25 @@ boost::signals2::connection LLIMFloater::setIMFloaterShowedCallback(const floate { return LLIMFloater::sIMFloaterShowedSignal.connect(cb); } + +// static +void build_names_string(const uuid_vec_t& uuids, std::string& names_string) +{ + std::vector avatar_names; + uuid_vec_t::const_iterator it = uuids.begin(); + for (; it != uuids.end(); ++it) + { + LLAvatarName av_name; + if (LLAvatarNameCache::get(*it, &av_name)) + { + avatar_names.push_back(av_name); + } + } + + // We should check whether the vector is not empty to pass the assertion + // that avatar_names.size() > 0 in LLAvatarActions::buildResidentsString. + if (!avatar_names.empty()) + { + LLAvatarActions::buildResidentsString(avatar_names, names_string); + } +} diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h index d98213b54c..4e09a24a09 100644 --- a/indra/newview/llimfloater.h +++ b/indra/newview/llimfloater.h @@ -89,7 +89,8 @@ public: void updateMessages(); void reloadMessages(); static void onSendMsg(LLUICtrl*, void*); - void sendMsg(); + void sendMsgFromInputEditor(); + void sendMsg(const std::string& msg); // callback for LLIMModel on new messages // route to specific floater if it is visible @@ -160,8 +161,9 @@ private: static void onInputEditorKeystroke(LLTextEditor* caller, void* userdata); void setTyping(bool typing); void onAddButtonClicked(); - void onAddSessionParticipants(const uuid_vec_t& uuids); - void addSessionParticipants(const LLSD& notification, const LLSD& response); + void addSessionParticipants(const uuid_vec_t& uuids); + void addP2PSessionParticipants(const uuid_vec_t& uuids); + void sendParticipantsAddedNotification(const uuid_vec_t& uuids); bool canAddSelectedToChat(const uuid_vec_t& uuids); void onCallButtonClicked(); diff --git a/indra/newview/skins/default/xui/en/floater_im_session.xml b/indra/newview/skins/default/xui/en/floater_im_session.xml index 2b63430106..de8d5f22fd 100644 --- a/indra/newview/skins/default/xui/en/floater_im_session.xml +++ b/indra/newview/skins/default/xui/en/floater_im_session.xml @@ -35,11 +35,14 @@ name="return_icon" value="Conv_toolbar_arrow_sw"/> + name="participant_added" + value="[NAME] was invited to the conversation.[NEW_WINDOW]"/> + name="multiple_participants_added" + value="[NAME] were invited to the conversation.[NEW_WINDOW]"/> + Date: Thu, 16 Aug 2012 04:55:48 +0300 Subject: CHUI-120 WIP Notifications about added chat participants should be sent to the conference when those participants actually join. - Removed notifying existing P2P participants about ad hoc conference staring in a new window. Now the notifications should arrive in that new window. - Fixed "Cancel" button which had no effect in adding P2P participants notification. --- indra/newview/llimfloater.cpp | 131 ++++++++++++++------- indra/newview/llimfloater.h | 4 +- .../skins/default/xui/en/floater_im_session.xml | 7 +- 3 files changed, 94 insertions(+), 48 deletions(-) diff --git a/indra/newview/llimfloater.cpp b/indra/newview/llimfloater.cpp index c3c9e334f2..0f0048b0d0 100644 --- a/indra/newview/llimfloater.cpp +++ b/indra/newview/llimfloater.cpp @@ -127,14 +127,13 @@ void LLIMFloater::refresh() // virtual void LLIMFloater::onClickCloseBtn() { - LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession( - mSessionID); + LLIMModel::LLIMSession* session = LLIMModel::instance().findIMSession(mSessionID); if (session == NULL) { llwarns << "Empty session." << llendl; return; -} + } bool is_call_with_chat = session->isGroupSessionType() || session->isAdHocSessionType() || session->isP2PSessionType(); @@ -228,7 +227,7 @@ void LLIMFloater::sendMsg(const std::string& msg) if (mSessionInitialized) { - LLIMModel::sendMessage(utf8_text, mSessionID, mOtherParticipantUUID, mDialog); + LLIMModel::sendMessage(utf8_text, mSessionID, mOtherParticipantUUID, mDialog); } else { @@ -261,7 +260,7 @@ void LLIMFloater::initIMSession(const LLUUID& session_id) mSession = LLIMModel::getInstance()->findIMSession(mSessionID); if (mSession) -{ + { mIsP2PChat = mSession->isP2PSessionType(); mSessionInitialized = mSession->mSessionInitialized; @@ -411,7 +410,7 @@ bool LLIMFloater::canAddSelectedToChat(const uuid_vec_t& uuids) if (speaker_mgr) { speaker_mgr->getSpeakerList(&speaker_list, true); - } + } for (uuid_vec_t::const_iterator id = uuids.begin(); id != uuids.end(); ++id) @@ -439,19 +438,24 @@ void LLIMFloater::addSessionParticipants(const uuid_vec_t& uuids) LLSD args; LLNotificationsUtil::add("ConfirmAddingChatParticipants", args, payload, - boost::bind(&LLIMFloater::addP2PSessionParticipants, this, uuids)); + boost::bind(&LLIMFloater::addP2PSessionParticipants, this, _1, _2, uuids)); } else { - sendParticipantsAddedNotification(uuids); - + // remember whom we have invited, to notify others later, when the invited ones actually join + mInvitedParticipants.insert(mInvitedParticipants.end(), uuids.begin(), uuids.end()); + inviteToSession(uuids); } } -void LLIMFloater::addP2PSessionParticipants(const uuid_vec_t& uuids) +void LLIMFloater::addP2PSessionParticipants(const LLSD& notification, const LLSD& response, const uuid_vec_t& uuids) { - sendParticipantsAddedNotification(uuids); + S32 option = LLNotificationsUtil::getSelectedOption(notification, response); + if (option != 0) + { + return; + } mStartConferenceInSameFloater = true; @@ -469,6 +473,12 @@ void LLIMFloater::addP2PSessionParticipants(const uuid_vec_t& uuids) // then we can close the current session onClose(false); + // we start a new session so reset the initialization flag + mSessionInitialized = false; + + // remember whom we have invited, to notify others later, when the invited ones actually join + mInvitedParticipants.insert(mInvitedParticipants.end(), uuids.begin(), uuids.end()); + // Start a new ad hoc voice call if we invite new participants to a P2P call, // or start a text chat otherwise. if (is_voice_call) @@ -487,7 +497,6 @@ void LLIMFloater::sendParticipantsAddedNotification(const uuid_vec_t& uuids) build_names_string(uuids, names_string); LLStringUtil::format_map_t args; args["[NAME]"] = names_string; - args["[NEW_WINDOW]"] = mIsP2PChat ? getString("new_window") : LLStringUtil::null; sendMsg(getString(uuids.size() > 1 ? "multiple_participants_added" : "participant_added", args)); } @@ -865,18 +874,20 @@ void LLIMFloater::sessionInitReplyReceived(const LLUUID& im_session_id) //*TODO here we should remove "starting session..." warning message if we added it in postBuild() (IB) - //need to send delayed messaged collected while waiting for session initialization + //need to send delayed messages collected while waiting for session initialization if (mQueuedMsgsForInit.size()) { - LLSD::array_iterator iter; - for ( iter = mQueuedMsgsForInit.beginArray(); - iter != mQueuedMsgsForInit.endArray(); ++iter) - { - LLIMModel::sendMessage(iter->asString(), mSessionID, - mOtherParticipantUUID, mDialog); + LLSD::array_iterator iter; + for ( iter = mQueuedMsgsForInit.beginArray(); + iter != mQueuedMsgsForInit.endArray(); ++iter) + { + LLIMModel::sendMessage(iter->asString(), mSessionID, + mOtherParticipantUUID, mDialog); + } + + mQueuedMsgsForInit.clear(); } } -} void LLIMFloater::appendMessage(const LLChat& chat, const LLSD &args) { @@ -1044,19 +1055,18 @@ void LLIMFloater::setTyping(bool typing) { LLIMModel::instance().sendTypingState(mSessionID, mOtherParticipantUUID, mMeTyping); - mShouldSendTypingState = false; - - } + mShouldSendTypingState = false; } + } if (!mIsNearbyChat) + { + LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); + if (speaker_mgr) { - LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID); - if (speaker_mgr) - { - speaker_mgr->setSpeakerTyping(gAgent.getID(), FALSE); + speaker_mgr->setSpeakerTyping(gAgent.getID(), FALSE); } -} + } } void LLIMFloater::processIMTyping(const LLIMInfo* im_info, BOOL typing) @@ -1075,29 +1085,66 @@ void LLIMFloater::processIMTyping(const LLIMInfo* im_info, BOOL typing) void LLIMFloater::processAgentListUpdates(const LLSD& body) { + uuid_vec_t joined_uuids; + if (body.isMap() && body.has("agent_updates") && body["agent_updates"].isMap()) { - LLSD agent_data = body["agent_updates"].get(gAgentID.asString()); - if (agent_data.isMap() && agent_data.has("info")) + LLSD::map_const_iterator update_it; + for(update_it = body["agent_updates"].beginMap(); + update_it != body["agent_updates"].endMap(); + ++update_it) { - LLSD agent_info = agent_data["info"]; + LLUUID agent_id(update_it->first); + LLSD agent_data = update_it->second; - if (agent_info.has("mutes")) + if (agent_data.isMap()) { - BOOL moderator_muted_text = agent_info["mutes"]["text"].asBoolean(); - mInputEditor->setEnabled(!moderator_muted_text); - std::string label; - if (moderator_muted_text) - label = LLTrans::getString("IM_muted_text_label"); - else - label = LLTrans::getString("IM_to_label") + " " + LLIMModel::instance().getName(mSessionID); - mInputEditor->setLabel(label); + // store the new participants in joined_uuids + if (agent_data.has("transition") && agent_data["transition"].asString() == "ENTER") + { + joined_uuids.push_back(agent_id); + } - if (moderator_muted_text) - LLNotificationsUtil::add("TextChatIsMutedByModerator"); + // process the moderator mutes + if (agent_id == gAgentID && agent_data.has("info") && agent_data["info"].has("mutes")) + { + BOOL moderator_muted_text = agent_data["info"]["mutes"]["text"].asBoolean(); + mInputEditor->setEnabled(!moderator_muted_text); + std::string label; + if (moderator_muted_text) + label = LLTrans::getString("IM_muted_text_label"); + else + label = LLTrans::getString("IM_to_label") + " " + LLIMModel::instance().getName(mSessionID); + mInputEditor->setLabel(label); + + if (moderator_muted_text) + LLNotificationsUtil::add("TextChatIsMutedByModerator"); + } } } } + + // the vectors need to be sorted for computing the intersection and difference + std::sort(mInvitedParticipants.begin(), mInvitedParticipants.end()); + std::sort(joined_uuids.begin(), joined_uuids.end()); + + uuid_vec_t intersection; // uuids of invited residents who have joined the conversation + std::set_intersection(mInvitedParticipants.begin(), mInvitedParticipants.end(), + joined_uuids.begin(), joined_uuids.end(), + std::back_inserter(intersection)); + + if (intersection.size() > 0) + { + sendParticipantsAddedNotification(intersection); + } + + // Remove all joined participants from invited array. + // The difference between the two vectors (the elements in mInvitedParticipants which are not in joined_uuids) + // is placed at the beginning of mInvitedParticipants, then all other elements are erased. + mInvitedParticipants.erase(std::set_difference(mInvitedParticipants.begin(), mInvitedParticipants.end(), + joined_uuids.begin(), joined_uuids.end(), + mInvitedParticipants.begin()), + mInvitedParticipants.end()); } void LLIMFloater::processSessionUpdate(const LLSD& session_update) diff --git a/indra/newview/llimfloater.h b/indra/newview/llimfloater.h index 4e09a24a09..f78fa46b6e 100644 --- a/indra/newview/llimfloater.h +++ b/indra/newview/llimfloater.h @@ -162,7 +162,7 @@ private: void setTyping(bool typing); void onAddButtonClicked(); void addSessionParticipants(const uuid_vec_t& uuids); - void addP2PSessionParticipants(const uuid_vec_t& uuids); + void addP2PSessionParticipants(const LLSD& notification, const LLSD& response, const uuid_vec_t& uuids); void sendParticipantsAddedNotification(const uuid_vec_t& uuids); bool canAddSelectedToChat(const uuid_vec_t& uuids); @@ -204,6 +204,8 @@ private: bool mStartConferenceInSameFloater; + uuid_vec_t mInvitedParticipants; + // connection to voice channel state change signal boost::signals2::connection mVoiceChannelStateChangeConnection; diff --git a/indra/newview/skins/default/xui/en/floater_im_session.xml b/indra/newview/skins/default/xui/en/floater_im_session.xml index de8d5f22fd..15d3dc30ae 100644 --- a/indra/newview/skins/default/xui/en/floater_im_session.xml +++ b/indra/newview/skins/default/xui/en/floater_im_session.xml @@ -36,13 +36,10 @@ value="Conv_toolbar_arrow_sw"/> + value="[NAME] was invited to the conversation."/> - + value="[NAME] were invited to the conversation."/>