From 37134720bce619a754ff097aff764d9a44bb0893 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 7 May 2025 22:29:08 +0300 Subject: [PATCH 1/3] #3757 Smarter subfolders dragndrop --- indra/newview/llinventorybridge.cpp | 38 +++++++++++++++++++----- indra/newview/llinventoryfunctions.cpp | 41 +++++++++++++++++++++++++- indra/newview/llinventoryfunctions.h | 3 +- indra/newview/llinventorygallery.cpp | 19 +++++++++--- 4 files changed, 87 insertions(+), 14 deletions(-) diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 4018a89c5a..bff7138282 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -2664,6 +2664,7 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, // bool is_movable = true; + bool create_outfit = false; if (is_movable && (marketplacelistings_id == cat_id)) { @@ -2708,7 +2709,12 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, tooltip_msg = LLTrans::getString("TooltipOutfitNotInInventory"); is_movable = false; } - else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear)) + else if (can_move_to_my_outfits_as_outfit(model, inv_cat, max_items_to_wear)) + { + is_movable = true; + create_outfit = true; + } + else if (can_move_to_my_outfits_as_subfolder(model, inv_cat)) { is_movable = true; } @@ -2742,7 +2748,12 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, is_movable = false; tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); } - else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear)) + else if (can_move_to_my_outfits_as_outfit(model, inv_cat, max_items_to_wear)) + { + is_movable = true; + create_outfit = true; + } + else if (can_move_to_my_outfits_as_subfolder(model, inv_cat)) { is_movable = true; } @@ -2943,7 +2954,7 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, if (mUUID == my_outifts_id) { EMyOutfitsSubfolderType inv_res = myoutfit_object_subfolder_type(model, cat_id, my_outifts_id); - if (inv_res == MY_OUTFITS_SUBFOLDER || inv_res == MY_OUTFITS_OUTFIT) + if (inv_res == MY_OUTFITS_SUBFOLDER || inv_res == MY_OUTFITS_OUTFIT || !create_outfit) { LLInvFVBridge::changeCategoryParent( model, @@ -2967,7 +2978,7 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, { case MY_OUTFITS_NO: // Moning from outside outfits into outfits - if (dest_res == MY_OUTFITS_SUBFOLDER) + if (dest_res == MY_OUTFITS_SUBFOLDER && create_outfit) { // turn it into outfit dropToMyOutfitsSubfolder(inv_cat, mUUID, LLFolderType::FT_OUTFIT, cb); @@ -4094,7 +4105,6 @@ void LLFolderBridge::perform_pasteFromClipboard() LLInventoryObject *obj = model->getObject(item_id); if (obj) { - if (move_is_into_lost_and_found) { if (LLAssetType::AT_CATEGORY == obj->getType()) @@ -4111,9 +4121,9 @@ void LLFolderBridge::perform_pasteFromClipboard() } else if (move_is_into_my_outfits && LLAssetType::AT_CATEGORY == obj->getType()) { - LLInventoryCategory* cat = model->getCategory(item_id); + LLViewerInventoryCategory* cat = model->getCategory(item_id); U32 max_items_to_wear = gSavedSettings.getU32("WearFolderLimit"); - if (cat && can_move_to_my_outfits(model, cat, max_items_to_wear)) + if (cat && can_move_to_my_outfits_as_outfit(model, cat, max_items_to_wear)) { if (mUUID == my_outifts_id) { @@ -4133,6 +4143,18 @@ void LLFolderBridge::perform_pasteFromClipboard() } } } + else if (cat && can_move_to_my_outfits_as_subfolder(model, cat)) + { + if (LLClipboard::instance().isCutMode()) + { + changeCategoryParent(model, cat, parent_id, false); + if (cb) cb->fire(item_id); + } + else + { + copy_inventory_category(model, cat, parent_id); + } + } else { LLNotificationsUtil::add("MyOutfitsPasteFailed"); @@ -4181,7 +4203,7 @@ void LLFolderBridge::perform_pasteFromClipboard() // move_inventory_item() is not enough, as we have to update inventory locally too if (LLAssetType::AT_CATEGORY == obj->getType()) { - LLViewerInventoryCategory* vicat = (LLViewerInventoryCategory *) model->getCategory(item_id); + LLViewerInventoryCategory* vicat = model->getCategory(item_id); llassert(vicat); if (vicat) { diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 7fff88fba7..9967318e92 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2314,7 +2314,7 @@ bool can_move_to_landmarks(LLInventoryItem* inv_item) } // Returns true if folder's content can be moved to Current Outfit or any outfit folder. -bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit) +bool can_move_to_my_outfits_as_outfit(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit) { LLInventoryModel::cat_array_t *cats; LLInventoryModel::item_array_t *items; @@ -2353,6 +2353,45 @@ bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_ca return true; } +bool can_move_to_my_outfits_as_subfolder(LLInventoryModel* model, LLInventoryCategory* inv_cat, S32 depth) +{ + LLInventoryModel::cat_array_t* cats; + LLInventoryModel::item_array_t* items; + model->getDirectDescendentsOf(inv_cat->getUUID(), cats, items); + + if (items->size() > 0) + { + // subfolders don't allow items + return false; + } + + constexpr size_t MAX_CONTENT = 255; + if (cats->size() > MAX_CONTENT) + { + // don't allow massive folders + return false; + } + + for (LLPointer& cat : *cats) + { + // outfits are valid to move, check non-outfit folders + if (cat->getPreferredType() != LLFolderType::FT_OUTFIT) + { + if (depth == 3) + { + // don't allow massive folders + return false; + } + if (!can_move_to_my_outfits_as_subfolder(model, cat, depth + 1)) + { + return false; + } + } + } + + return true; +} + std::string get_localized_folder_name(LLUUID cat_uuid) { std::string localized_root_name; diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 0ab045f2a0..f56413bf5d 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -112,7 +112,8 @@ std::string get_category_path(LLUUID cat_id); bool can_move_to_outfit(LLInventoryItem* inv_item, bool move_is_into_current_outfit); bool can_move_to_landmarks(LLInventoryItem* inv_item); -bool can_move_to_my_outfits(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit); +bool can_move_to_my_outfits_as_outfit(LLInventoryModel* model, LLInventoryCategory* inv_cat, U32 wear_limit); +bool can_move_to_my_outfits_as_subfolder(LLInventoryModel* model, LLInventoryCategory* inv_cat, S32 depth = 0); std::string get_localized_folder_name(LLUUID cat_uuid); void new_folder_window(const LLUUID& folder_id); void ungroup_folder_items(const LLUUID& folder_id); diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp index eb47af85fd..3222dff1b2 100644 --- a/indra/newview/llinventorygallery.cpp +++ b/indra/newview/llinventorygallery.cpp @@ -3714,6 +3714,7 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, // bool is_movable = true; + bool create_outfit = false; if (is_movable && (marketplacelistings_id == cat_id)) { @@ -3759,7 +3760,12 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, tooltip_msg = LLTrans::getString("TooltipOutfitNotInInventory"); is_movable = false; } - else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear)) + else if (can_move_to_my_outfits_as_outfit(model, inv_cat, max_items_to_wear)) + { + is_movable = true; + create_outfit = true; + } + else if (can_move_to_my_outfits_as_subfolder(model, inv_cat)) { is_movable = true; } @@ -3793,7 +3799,12 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, is_movable = false; tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); } - else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear)) + else if (can_move_to_my_outfits_as_outfit(model, inv_cat, max_items_to_wear)) + { + is_movable = true; + create_outfit = true; + } + else if (can_move_to_my_outfits_as_subfolder(model, inv_cat)) { is_movable = true; } @@ -3928,7 +3939,7 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, if (dest_id == my_outifts_id) { EMyOutfitsSubfolderType inv_res = myoutfit_object_subfolder_type(model, cat_id, my_outifts_id); - if (inv_res == MY_OUTFITS_SUBFOLDER || inv_res == MY_OUTFITS_OUTFIT) + if (inv_res == MY_OUTFITS_SUBFOLDER || inv_res == MY_OUTFITS_OUTFIT || !create_outfit) { gInventory.changeCategoryParent( (LLViewerInventoryCategory*)inv_cat, @@ -3950,7 +3961,7 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, { case MY_OUTFITS_NO: // Moning from outside outfits into outfits - if (dest_res == MY_OUTFITS_SUBFOLDER) + if (dest_res == MY_OUTFITS_SUBFOLDER && create_outfit) { // turn it into outfit dropToMyOutfitsSubfolder(inv_cat, dest_id, LLFolderType::FT_OUTFIT); From 377d1b3813077619fc795f54f93b0d478cf03cbd Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Thu, 8 May 2025 19:35:19 +0300 Subject: [PATCH 2/3] #4010 Add audio ping for chat mentions --- indra/newview/app_settings/settings.xml | 33 +++++++++++++++++++ indra/newview/llimview.cpp | 19 ++++++++--- indra/newview/llvieweraudio.cpp | 1 + .../default/xui/en/panel_preferences_chat.xml | 25 +++++++++----- 4 files changed, 65 insertions(+), 13 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 1025c9299d..61d2013224 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -6361,6 +6361,17 @@ Value 0 + PlaySoundChatMention + + Comment + Plays a sound when got mentioned in a chat + Persist + 1 + Type + Boolean + Value + 0 + PluginAttachDebuggerToPlugins Comment @@ -12395,6 +12406,28 @@ Value 2ca849ba-2885-4bc3-90ef-d4987a5b983a + UISndChatMention + + Comment + Sound file for chat mention(uuid for sound asset) + Persist + 1 + Type + String + Value + 03e77cb5-592c-5b33-d271-2e46497c3fb3 + + UISndChatPing + + Comment + Sound file for chat ping(uuid for sound asset) + Persist + 1 + Type + String + Value + 7dd36df6-2624-5438-f988-fdf8588a0ad9 + UISndClick Comment diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 23bba99ed6..6f085adcbd 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -199,6 +199,8 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg) bool store_dnd_message = false; // flag storage of a dnd message bool is_session_focused = session_floater->isTornOff() && session_floater->hasFocus(); bool contains_mention = LLUrlRegistry::getInstance()->containsAgentMention(msg["message"].asString()); + static LLCachedControl play_snd_mention_pref(gSavedSettings, "PlaySoundChatMention", false); + bool play_snd_mention = contains_mention && play_snd_mention_pref && (msg["source_type"].asInteger() != CHAT_SOURCE_OBJECT); if (!LLFloater::isVisible(im_box) || im_box->isMinimized()) { conversations_floater_status = CLOSED; @@ -232,7 +234,7 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg) else { user_preferences = gSavedSettings.getString("NotificationNearbyChatOptions"); - if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNearbyChatIM"))) + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNearbyChatIM")) && !play_snd_mention) { make_ui_sound("UISndNewIncomingIMSession"); } @@ -243,7 +245,7 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg) if (LLAvatarTracker::instance().isBuddy(participant_id)) { user_preferences = gSavedSettings.getString("NotificationFriendIMOptions"); - if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundFriendIM"))) + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundFriendIM")) && !play_snd_mention) { make_ui_sound("UISndNewIncomingIMSession"); } @@ -251,7 +253,7 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg) else { user_preferences = gSavedSettings.getString("NotificationNonFriendIMOptions"); - if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNonFriendIM"))) + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundNonFriendIM")) && !play_snd_mention) { make_ui_sound("UISndNewIncomingIMSession"); } @@ -260,7 +262,7 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg) else if (session->isAdHocSessionType()) { user_preferences = gSavedSettings.getString("NotificationConferenceIMOptions"); - if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundConferenceIM"))) + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundConferenceIM")) && !play_snd_mention) { make_ui_sound("UISndNewIncomingIMSession"); } @@ -268,11 +270,18 @@ void notify_of_message(const LLSD& msg, bool is_dnd_msg) else if(session->isGroupSessionType()) { user_preferences = gSavedSettings.getString("NotificationGroupChatOptions"); - if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundGroupChatIM"))) + if (!gAgent.isDoNotDisturb() && (gSavedSettings.getBOOL("PlaySoundGroupChatIM")) && !play_snd_mention) { make_ui_sound("UISndNewIncomingIMSession"); } } + if (play_snd_mention) + { + if (!gAgent.isDoNotDisturb()) + { + make_ui_sound("UISndChatMention"); + } + } // actions: diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp index 404297c58f..aa0cbac91f 100644 --- a/indra/newview/llvieweraudio.cpp +++ b/indra/newview/llvieweraudio.cpp @@ -390,6 +390,7 @@ void init_audio() gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndWindowClose"))); gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndWindowOpen"))); gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndRestart"))); + gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndChatMention"))); } audio_update_volume(true); diff --git a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml index 88716c7f96..0aa1af7de6 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_chat.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_chat.xml @@ -409,7 +409,7 @@ layout="topleft" left="0" name="play_sound" - width="100" + width="90" top_pad="8" visible="true"> Play sound: @@ -419,10 +419,10 @@ height="16" label="New conversation" layout="topleft" - left_pad="15" + left_pad="5" top_pad="-10" name="new_conversation" - width="150" /> + width="130" /> + width="130" /> + width="130" /> + width="130" /> + From 9668d2f0eff761f1de71cea718a46e807f9c00a8 Mon Sep 17 00:00:00 2001 From: Maxim Nikolenko Date: Fri, 9 May 2025 18:46:56 +0300 Subject: [PATCH 3/3] #3758 do not reopen avatar picker floater --- indra/llui/llchatmentionhelper.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/indra/llui/llchatmentionhelper.cpp b/indra/llui/llchatmentionhelper.cpp index f7769b2cbe..5745389a58 100644 --- a/indra/llui/llchatmentionhelper.cpp +++ b/indra/llui/llchatmentionhelper.cpp @@ -98,7 +98,14 @@ void LLChatMentionHelper::showHelper(LLUICtrl* host_ctrl, S32 local_x, S32 local LLRect rect = av_picker_floater->getRect(); rect.setLeftTopAndSize(floater_x, floater_y + rect.getHeight(), rect.getWidth(), rect.getHeight()); av_picker_floater->setRect(rect); - av_picker_floater->openFloater(LLSD().with("av_name", av_name)); + if (av_picker_floater->isShown()) + { + av_picker_floater->onOpen(LLSD().with("av_name", av_name)); + } + else + { + av_picker_floater->openFloater(LLSD().with("av_name", av_name)); + } } void LLChatMentionHelper::hideHelper(const LLUICtrl* ctrl)