diff options
author | Erik Kundiman <erik@megapahit.org> | 2025-08-02 06:56:07 +0800 |
---|---|---|
committer | Erik Kundiman <erik@megapahit.org> | 2025-08-02 06:56:07 +0800 |
commit | 51743334b81e5aa4be59417a80149d5f416b51f3 (patch) | |
tree | 5600f9f58389fe31b71e570bac7867d991408cf1 | |
parent | cb759bf9e0580b0c0799e33b8e7af1ea46a4c336 (diff) | |
parent | 7588afc86a016c00e6263284bc0db6d684c43895 (diff) |
Merge branch 'main' into 2025.05
-rw-r--r-- | indra/newview/llagent.cpp | 6 | ||||
-rw-r--r-- | indra/newview/llagent.h | 3 | ||||
-rw-r--r-- | indra/newview/llappviewer.cpp | 123 | ||||
-rw-r--r-- | indra/newview/llappviewer.h | 4 | ||||
-rw-r--r-- | indra/newview/llavatarlist.cpp | 67 | ||||
-rw-r--r-- | indra/newview/llavatarlist.h | 2 | ||||
-rw-r--r-- | indra/newview/llfloaterpreference.cpp | 2 | ||||
-rw-r--r-- | indra/newview/llpanelpeople.cpp | 8 | ||||
-rw-r--r-- | indra/newview/llspeakers.cpp | 4 | ||||
-rw-r--r-- | indra/newview/llstartup.cpp | 4 | ||||
-rw-r--r-- | indra/newview/llviewermessage.cpp | 3 | ||||
-rw-r--r-- | indra/newview/llvoavatar.cpp | 53 |
12 files changed, 156 insertions, 123 deletions
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 9ce14eb0ab..8422294ac7 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -1305,6 +1305,12 @@ const LLVector3 &LLAgent::getPositionAgent() return mFrameAgent.getOrigin(); } +void LLAgent::setAvatarsPositions(const std::map<LLUUID, LLVector3d>& avatarsPositions) +{ + mAvatarsPositions.clear(); + mAvatarsPositions = avatarsPositions; +} + boost::signals2::connection LLAgent::whenPositionChanged(position_signal_t::slot_type fn) { return mOnPositionChanged.connect(fn); diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index b475782946..a2d2ecea9f 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -195,6 +195,8 @@ public: // Call once per frame to update position, angles (radians). void updateAgentPosition(const F32 dt, const F32 yaw, const S32 mouse_x, const S32 mouse_y); void setPositionAgent(const LLVector3 ¢er); + void setAvatarsPositions(const std::map<LLUUID, LLVector3d>& avatarsPositions); + const std::map<LLUUID, LLVector3d>& getAvatarsPositions() const { return mAvatarsPositions;} boost::signals2::connection whenPositionChanged(position_signal_t::slot_type fn); @@ -205,6 +207,7 @@ private: position_signal_t mOnPositionChanged; LLVector3d mLastTestGlobal; + std::map<LLUUID, LLVector3d> mAvatarsPositions; //-------------------------------------------------------------------- // Velocity diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 8eabf0a5d1..c13fd397b1 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -283,6 +283,9 @@ using namespace LL; #include <discordpp.h> static std::shared_ptr<discordpp::Client> gDiscordClient; static uint64_t gDiscordTimestampsStart; +static std::string gDiscordActivityDetails; +static int32_t gDiscordPartyCurrentSize; +static int32_t gDiscordPartyMaxSize; #endif static LLAppViewerListener sAppViewerListener(LLAppViewer::instance); @@ -1356,7 +1359,10 @@ bool LLAppViewer::doFrame() TimePoint fpsLimitFrameStartTime = std::chrono::steady_clock::now(); #ifdef LL_DISCORD - discordpp::RunCallbacks(); + { + LL_PROFILE_ZONE_NAMED("discord_callbacks"); + discordpp::RunCallbacks(); + } #endif LL_RECORD_BLOCK_TIME(FTM_FRAME); @@ -5950,6 +5956,8 @@ void LLAppViewer::metricsSend(bool enable_reporting) void LLAppViewer::initDiscordSocial() { + gDiscordPartyCurrentSize = 1; + gDiscordPartyMaxSize = 0; gDiscordTimestampsStart = time(nullptr); gDiscordClient = std::make_shared<discordpp::Client>(); gDiscordClient->SetStatusChangedCallback([](discordpp::Client::Status status, discordpp::Client::Error, int32_t) { @@ -5960,14 +5968,25 @@ void LLAppViewer::initDiscordSocial() }); if (gSavedSettings.getBOOL("EnableDiscord")) { - gDiscordClient->UpdateToken(discordpp::AuthorizationTokenType::Bearer, gSecAPIHandler->loadCredential("Discord")->getAuthenticator()["token"].asString(), [](discordpp::ClientResult result) { - if (result.Successful()) - gDiscordClient->Connect(); - }); + auto credential = gSecAPIHandler->loadCredential("Discord"); + if (credential.notNull()) + { + gDiscordClient->UpdateToken(discordpp::AuthorizationTokenType::Bearer, credential->getAuthenticator()["token"].asString(), [](discordpp::ClientResult result) { + if (result.Successful()) + gDiscordClient->Connect(); + else + LL_WARNS("Discord") << result.Error() << LL_ENDL; + }); + } + else + { + LL_WARNS("Discord") << "Integration was enabled, but no credentials. Disabling integration." << LL_ENDL; + gSavedSettings.setBOOL("EnableDiscord", false); + } } } -void LLAppViewer::handleDiscordSocial(const LLSD& value) +void LLAppViewer::toggleDiscordIntegration(const LLSD& value) { static const uint64_t APPLICATION_ID = 1393451183741599796; if (value.asBoolean()) @@ -5981,34 +6000,60 @@ void LLAppViewer::handleDiscordSocial(const LLSD& value) if (result.Successful()) { gDiscordClient->GetToken(APPLICATION_ID, code, codeVerifier.Verifier(), redirectUri, [](discordpp::ClientResult result, std::string accessToken, std::string, discordpp::AuthorizationTokenType, int32_t, std::string) { - gDiscordClient->UpdateToken(discordpp::AuthorizationTokenType::Bearer, accessToken, [](discordpp::ClientResult result) { - if (result.Successful()) - gDiscordClient->Connect(); - }); - LLSD authenticator = LLSD::emptyMap(); - authenticator["token"] = accessToken; - gSecAPIHandler->saveCredential(gSecAPIHandler->createCredential("Discord", LLSD::emptyMap(), authenticator), true); + if (result.Successful()) + { + gDiscordClient->UpdateToken(discordpp::AuthorizationTokenType::Bearer, accessToken, [accessToken](discordpp::ClientResult result) { + if (result.Successful()) + { + LLSD authenticator = LLSD::emptyMap(); + authenticator["token"] = accessToken; + gSecAPIHandler->saveCredential(gSecAPIHandler->createCredential("Discord", LLSD::emptyMap(), authenticator), true); + gDiscordClient->Connect(); + } + else + { + LL_WARNS("Discord") << result.Error() << LL_ENDL; + } + }); + } + else + { + LL_WARNS("Discord") << result.Error() << LL_ENDL; + } }); } else { + LL_WARNS("Discord") << result.Error() << LL_ENDL; gSavedSettings.setBOOL("EnableDiscord", false); } }); } else { - gDiscordClient->RevokeToken(APPLICATION_ID, gSecAPIHandler->loadCredential("Discord")->getAuthenticator()["token"].asString(), [](discordpp::ClientResult result) { - if (result.Successful()) - gDiscordClient->Disconnect(); + gDiscordClient->Disconnect(); + auto credential = gSecAPIHandler->loadCredential("Discord"); + if (credential.notNull()) + { + gDiscordClient->RevokeToken(APPLICATION_ID, credential->getAuthenticator()["token"].asString(), [](discordpp::ClientResult result) { + if (result.Successful()) + LL_INFOS("Discord") << "Access token successfully revoked." << LL_ENDL; + else + LL_WARNS("Discord") << "No access token to revoke." << LL_ENDL; + }); auto cred = new LLCredential("Discord"); gSecAPIHandler->deleteCredential(cred); - }); + } + else + { + LL_WARNS("Discord") << "Credentials are already nonexistent." << LL_ENDL; + } } } void LLAppViewer::updateDiscordActivity() { + LL_PROFILE_ZONE_SCOPED; discordpp::Activity activity; activity.SetType(discordpp::ActivityTypes::Playing); discordpp::ActivityTimestamps timestamps; @@ -6021,18 +6066,23 @@ void LLAppViewer::updateDiscordActivity() return; } - if (gSavedSettings.getBOOL("ShowDiscordActivityDetails")) + static LLCachedControl<bool> show_details(gSavedSettings, "ShowDiscordActivityDetails", false); + if (show_details) { - LLAvatarName av_name; - LLAvatarNameCache::get(gAgent.getID(), &av_name); - auto name = av_name.getUserName(); - auto displayName = av_name.getDisplayName(); - if (name != displayName) - name = displayName + " (" + name + ")"; - activity.SetDetails(name); + if (gDiscordActivityDetails.empty()) + { + LLAvatarName av_name; + LLAvatarNameCache::get(gAgent.getID(), &av_name); + gDiscordActivityDetails = av_name.getUserName(); + auto displayName = av_name.getDisplayName(); + if (gDiscordActivityDetails != displayName) + gDiscordActivityDetails = displayName + " (" + gDiscordActivityDetails + ")"; + } + activity.SetDetails(gDiscordActivityDetails); } - if (gSavedSettings.getBOOL("ShowDiscordActivityState")) + static LLCachedControl<bool> show_state(gSavedSettings, "ShowDiscordActivityState", false); + if (show_state) { auto agent_pos_region = gAgent.getPositionAgent(); S32 pos_x = S32(agent_pos_region.mV[VX] + 0.5f); @@ -6056,19 +6106,26 @@ void LLAppViewer::updateDiscordActivity() auto location = llformat("%s (%d, %d, %d)", gAgent.getRegion()->getName().c_str(), pos_x, pos_y, pos_z); activity.SetState(location); - auto world = LLWorld::getInstance(); - uuid_vec_t chat_radius_uuids, near_me_uuids; - auto position = gAgent.getPositionGlobal(); - world->getAvatars(&chat_radius_uuids, NULL, position, CHAT_NORMAL_RADIUS); - world->getAvatars(&near_me_uuids, NULL, position, gSavedSettings.getF32("MPVNearMeRange")); discordpp::ActivityParty party; party.SetId(location); - party.SetCurrentSize(chat_radius_uuids.size()); - party.SetMaxSize(near_me_uuids.size()); + party.SetCurrentSize(gDiscordPartyCurrentSize); + party.SetMaxSize(gDiscordPartyMaxSize); activity.SetParty(party); } gDiscordClient->UpdateRichPresence(activity, [](discordpp::ClientResult) {}); } +void LLAppViewer::updateDiscordPartyCurrentSize(int32_t size) +{ + gDiscordPartyCurrentSize = size; + updateDiscordActivity(); +} + +void LLAppViewer::updateDiscordPartyMaxSize(int32_t size) +{ + gDiscordPartyMaxSize = size; + updateDiscordActivity(); +} + #endif diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 3b6488dade..14e96afe94 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -253,8 +253,10 @@ public: #ifdef LL_DISCORD static void initDiscordSocial(); - static void handleDiscordSocial(const LLSD& value); + static void toggleDiscordIntegration(const LLSD& value); static void updateDiscordActivity(); + static void updateDiscordPartyCurrentSize(int32_t size); + static void updateDiscordPartyMaxSize(int32_t size); #endif protected: diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp index 5f9d03ca66..e29be0c757 100644 --- a/indra/newview/llavatarlist.cpp +++ b/indra/newview/llavatarlist.cpp @@ -48,12 +48,11 @@ #include "llvoiceclient.h" #include "llviewercontrol.h" // for gSavedSettings #include "lltooldraganddrop.h" -#include "llworld.h" static LLDefaultChildRegistry::Register<LLAvatarList> r("avatar_list"); // Last interaction time update period. -static const F32 LIT_UPDATE_PERIOD = 1; +static const F32 LIT_UPDATE_PERIOD = 5; // Maximum number of avatars that can be added to a list in one pass. // Used to limit time spent for avatar list update per frame. @@ -205,13 +204,25 @@ void LLAvatarList::draw() if ((mShowLastInteractionTime || mAvatarDistance || mAvatarArrivalTime) && mLITUpdateTimer->hasExpired()) { - if (mAvatarArrivalTime) + if (mAvatarArrivalTime || mAvatarDistance) { - updateAvatarArrivalTime(); - } - if (mAvatarDistance) - { - updateAvatarDistance(); + std::vector<LLPanel*> items; + getItems(items); + for (auto it = items.begin(); it != items.end(); it++) + { + auto item = static_cast<LLAvatarListItem*>(*it); + if (mAvatarArrivalTime) + { + auto secs_since = LLDate::now().secondsSinceEpoch() - LLRecentPeople::instance().getArrivalTimeByID(item->getAvatarId()); + if (secs_since >= 0) + item->setAvatarArrivalTime(secs_since); + } + if (mAvatarDistance) + { + auto avatarsPositions = gAgent.getAvatarsPositions(); + item->setAvatarDistance(dist_vec(avatarsPositions[item->getAvatarId()], gAgent.getPositionGlobal())); + } + } } if (mShowLastInteractionTime) { @@ -554,46 +565,6 @@ void LLAvatarList::computeDifference( LLCommonUtils::computeDifference(vnew_unsorted, vcur, vadded, vremoved); } -void LLAvatarList::updateAvatarArrivalTime() -{ - std::vector<LLPanel*> items; - getItems(items); - auto uuids = getIDs(); - std::vector<LLVector3d> positions; - auto me_pos = gAgent.getPositionGlobal(); - LLWorld::getInstance()->getAvatars(&uuids, &positions, me_pos, gSavedSettings.getF32("MPVNearMeRange")); - LLRecentPeople::instance().updateAvatarsArrivalTime(uuids); - for (auto it = items.begin(); it != items.end(); it++) - { - auto item = static_cast<LLAvatarListItem*>(*it); - auto secs_since = LLDate::now().secondsSinceEpoch() - LLRecentPeople::instance().getArrivalTimeByID(item->getAvatarId()); - if (secs_since >= 0) - item->setAvatarArrivalTime(secs_since); - } -} - - void LLAvatarList::updateAvatarDistance() -{ - std::vector<LLPanel*> items; - getItems(items); - auto uuids = getIDs(); - std::vector<LLVector3d> positions; - auto me_pos = gAgent.getPositionGlobal(); - LLWorld::getInstance()->getAvatars(&uuids, &positions, me_pos, gSavedSettings.getF32("MPVNearMeRange")); - std::map <LLUUID, LLVector3d> avatarsPositions; - auto pos_it = positions.begin(); - auto id_it = uuids.begin(); - for (;pos_it != positions.end() && id_it != uuids.end(); ++pos_it, ++id_it) - { - avatarsPositions[*id_it] = *pos_it; - } - for (auto it = items.begin(); it != items.end(); it++) - { - auto item = static_cast<LLAvatarListItem*>(*it); - item->setAvatarDistance(dist_vec(avatarsPositions[item->getAvatarId()], me_pos)); - } -} - // Refresh shown time of our last interaction with all listed avatars. void LLAvatarList::updateLastInteractionTimes() { diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h index 97b4f05985..e6e0728a3f 100644 --- a/indra/newview/llavatarlist.h +++ b/indra/newview/llavatarlist.h @@ -114,8 +114,6 @@ protected: const uuid_vec_t& vnew, uuid_vec_t& vadded, uuid_vec_t& vremoved); - void updateAvatarArrivalTime(); - void updateAvatarDistance(); void updateLastInteractionTimes(); void rebuildNames(); void onItemDoubleClicked(LLUICtrl* ctrl, S32 x, S32 y, MASK mask); diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 4c8122bf71..2a6360cef8 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -367,7 +367,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.DeleteTranscripts", boost::bind(&LLFloaterPreference::onDeleteTranscripts, this)); mCommitCallbackRegistrar.add("UpdateFilter", boost::bind(&LLFloaterPreference::onUpdateFilterTerm, this, false)); // <FS:ND/> Hook up for filtering #ifdef LL_DISCORD - gSavedSettings.getControl("EnableDiscord")->getCommitSignal()->connect(boost::bind(&LLAppViewer::handleDiscordSocial, _2)); + gSavedSettings.getControl("EnableDiscord")->getCommitSignal()->connect(boost::bind(&LLAppViewer::toggleDiscordIntegration, _2)); gSavedSettings.getControl("ShowDiscordActivityDetails")->getCommitSignal()->connect(boost::bind(&LLAppViewer::updateDiscordActivity)); gSavedSettings.getControl("ShowDiscordActivityState")->getCommitSignal()->connect(boost::bind(&LLAppViewer::updateDiscordActivity)); #endif diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp index 72fa553023..aca8cf189b 100644 --- a/indra/newview/llpanelpeople.cpp +++ b/indra/newview/llpanelpeople.cpp @@ -160,6 +160,7 @@ public: mAvatarsPositions[*id_it] = *pos_it; } }; + const id_to_pos_map_t& getAvatarsPositions() const { return mAvatarsPositions; } protected: virtual bool doCompare(const LLAvatarListItem* item1, const LLAvatarListItem* item2) const @@ -843,8 +844,13 @@ void LLPanelPeople::updateNearbyList() LLWorld::getInstance()->getAvatars(&mNearbyList->getIDs(), &positions, gAgent.getPositionGlobal(), gSavedSettings.getF32("MPVNearMeRange")); mNearbyList->setDirty(); +#ifdef LL_DISCORD + if (gSavedSettings.getBOOL("EnableDiscord")) + LLAppViewer::updateDiscordPartyMaxSize(mNearbyList->getIDs().size()); +#endif DISTANCE_COMPARATOR.updateAvatarsPositions(positions, mNearbyList->getIDs()); + gAgent.setAvatarsPositions(DISTANCE_COMPARATOR.getAvatarsPositions()); LLActiveSpeakerMgr::instance().update(true); } @@ -1565,7 +1571,7 @@ bool LLPanelPeople::updateNearbyArrivalTime() { std::vector<LLVector3d> positions; std::vector<LLUUID> uuids; - static LLCachedControl<F32> range(gSavedSettings, "NearMeRange"); + static LLCachedControl<F32> range(gSavedSettings, "MPVNearMeRange"); LLWorld::getInstance()->getAvatars(&uuids, &positions, gAgent.getPositionGlobal(), range); LLRecentPeople::instance().updateAvatarsArrivalTime(uuids); return LLApp::isExiting(); diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index 4956c188fb..12a9d5e9b7 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -1026,6 +1026,10 @@ void LLLocalSpeakerMgr::updateSpeakerList() uuid_vec_t avatar_ids; std::vector<LLVector3d> positions; LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, gAgent.getPositionGlobal(), CHAT_NORMAL_RADIUS); +#ifdef LL_DISCORD + if (gSavedSettings.getBOOL("EnableDiscord")) + LLAppViewer::updateDiscordPartyCurrentSize(avatar_ids.size()); +#endif for(U32 i=0; i<avatar_ids.size(); i++) { setSpeaker(avatar_ids[i]); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index dfad169813..8d010553a0 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2327,10 +2327,6 @@ bool idle_startup() do_startup_frame(); } -#ifdef LL_DISCORD - LLAppViewer::updateDiscordActivity(); -#endif - return true; } diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index d6f1b96a7b..86bd11d1eb 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -3073,7 +3073,8 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) } #ifdef LL_DISCORD - LLAppViewer::updateDiscordActivity(); + if (gSavedSettings.getBOOL("EnableDiscord")) + LLAppViewer::updateDiscordActivity(); #endif if ( LLTracker::isTracking(NULL) ) diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 8c3f219182..d7f6852c38 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -818,15 +818,14 @@ LLVOAvatar::~LLVOAvatar() { sInstances.remove(this); - if (gSavedSettings.getBOOL("IMShowArrivalsDepartures")) + static LLCachedControl<bool> show_arrival_departures(gSavedSettings, "IMShowArrivalsDepartures", false); + if (show_arrival_departures) { - LLAvatarName av_name; - LLAvatarNameCache::get(getID(), &av_name); - auto display_name = av_name.getDisplayName(); - if (!display_name.empty()) + auto full_name = getFullname(); + if (!full_name.empty()) { - LLChat chat{llformat("%s left.", display_name.c_str())}; - chat.mFromName = display_name; + LLChat chat{llformat("%s left.", full_name.c_str())}; + chat.mFromName = full_name; chat.mFromID = getID(); LLSD args; args["COLOR"] = "ChatHistoryTextColor"; @@ -2583,31 +2582,21 @@ U32 LLVOAvatar::processUpdateMessage(LLMessageSystem *mesgsys, { mDebugExistenceTimer.reset(); debugAvatarRezTime("AvatarRezArrivedNotification", "avatar arrived"); - if (gSavedSettings.getBOOL("IMShowArrivalsDepartures")) - { - uuid_vec_t uuids; - std::vector<LLVector3d> positions; - LLWorld::getInstance()->getAvatars(&uuids, &positions, gAgent.getPositionGlobal(), gSavedSettings.getF32("MPVNearMeRange")); - auto pos_it = positions.begin(); - auto id_it = uuids.begin(); - for (;pos_it != positions.end() && id_it != uuids.end(); ++pos_it, ++id_it) - { - if (*id_it == getID() && !isSelf()) - { - LLAvatarName av_name; - LLAvatarNameCache::get(getID(), &av_name); - auto display_name = av_name.getDisplayName(); - if (!display_name.empty()) - { - LLChat chat{llformat("%s arrived (%.1f m).", display_name.c_str(), dist_vec(*pos_it, gAgent.getPositionGlobal()))}; - chat.mFromName = display_name; - chat.mFromID = getID(); - LLSD args; - args["COLOR"] = "ChatHistoryTextColor"; - LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args); - } - break; - } + static LLCachedControl<bool> show_arrival_departures(gSavedSettings, "IMShowArrivalsDepartures", false); + if (show_arrival_departures) + { + auto full_name = getFullname(); + if (!full_name.empty()) + { + auto avatarsPositions = gAgent.getAvatarsPositions(); + auto id = getID(); + auto avatarPosition = avatarsPositions[id]; + LLChat chat{std::string{full_name + " arrived" + (avatarPosition.isExactlyZero() ? "" : llformat(" (%.1f m)", dist_vec(avatarPosition, gAgent.getPositionGlobal()))) + "."}}; + chat.mFromName = full_name; + chat.mFromID = id; + LLSD args; + args["COLOR"] = "ChatHistoryTextColor"; + LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args); } } } |