summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llui/llmenugl.cpp3
-rw-r--r--indra/newview/llavataractions.cpp12
-rw-r--r--indra/newview/llavataractions.h5
-rw-r--r--indra/newview/llchathistory.cpp264
-rw-r--r--indra/newview/llfloaterimcontainer.cpp22
-rw-r--r--indra/newview/llfloaterimcontainer.h1
-rw-r--r--indra/newview/llinventorymodel.cpp38
-rw-r--r--indra/newview/llinventorymodel.h3
-rw-r--r--indra/newview/llinventorypanel.cpp13
-rw-r--r--indra/newview/llviewermessage.cpp5
-rw-r--r--indra/newview/skins/default/xui/en/menu_avatar_icon.xml44
11 files changed, 343 insertions, 67 deletions
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 022f814bbc..0d42f726fa 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -3331,6 +3331,7 @@ BOOL LLMenuBarGL::handleAcceleratorKey(KEY key, MASK mask)
if (getHighlightedItem())
{
clearHoverItem();
+ LLMenuGL::setKeyboardMode(FALSE);
}
else
{
@@ -3777,10 +3778,10 @@ BOOL LLMenuHolderGL::hideMenus()
{
return FALSE;
}
+ LLMenuGL::setKeyboardMode(FALSE);
BOOL menu_visible = hasVisibleMenu();
if (menu_visible)
{
- LLMenuGL::setKeyboardMode(FALSE);
// clicked off of menu, hide them all
for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it)
{
diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index 219d9da01f..8fe684ad79 100644
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -1005,7 +1005,7 @@ void LLAvatarActions::toggleBlock(const LLUUID& id)
}
// static
-void LLAvatarActions::toggleMuteVoice(const LLUUID& id)
+void LLAvatarActions::toggleMute(const LLUUID& id, U32 flags)
{
LLAvatarName av_name;
LLAvatarNameCache::get(id, &av_name);
@@ -1016,15 +1016,21 @@ void LLAvatarActions::toggleMuteVoice(const LLUUID& id)
LLMute mute(id, av_name.getUserName(), LLMute::AGENT);
if (!is_muted)
{
- mute_list->add(mute, LLMute::flagVoiceChat);
+ mute_list->add(mute, flags);
}
else
{
- mute_list->remove(mute, LLMute::flagVoiceChat);
+ mute_list->remove(mute, flags);
}
}
// static
+void LLAvatarActions::toggleMuteVoice(const LLUUID& id)
+{
+ toggleMute(id, LLMute::flagVoiceChat);
+}
+
+// static
bool LLAvatarActions::canOfferTeleport(const LLUUID& id)
{
// First use LLAvatarTracker::isBuddy()
diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h
index 256d44d820..b56d5b0fb9 100644
--- a/indra/newview/llavataractions.h
+++ b/indra/newview/llavataractions.h
@@ -131,6 +131,11 @@ public:
static void toggleBlock(const LLUUID& id);
/**
+ * Mute/unmute avatar.
+ */
+ static void toggleMute(const LLUUID& id, U32 flags);
+
+ /**
* Block/unblock the avatar voice.
*/
static void toggleMuteVoice(const LLUUID& id);
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index 9798ef3529..5748eeec47 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -38,10 +38,14 @@
#include "llpanel.h"
#include "lluictrlfactory.h"
#include "llscrollcontainer.h"
-#include "llavatariconctrl.h"
-#include "llcallingcard.h" //for LLAvatarTracker
+#include "llagent.h"
#include "llagentdata.h"
#include "llavataractions.h"
+#include "llavatariconctrl.h"
+#include "llcallingcard.h" //for LLAvatarTracker
+#include "llgroupactions.h"
+#include "llgroupmgr.h"
+#include "llspeakers.h" //for LLIMSpeakerMgr
#include "lltrans.h"
#include "llfloaterreg.h"
#include "llfloatersidepanelcontainer.h"
@@ -49,7 +53,6 @@
#include "llstylemap.h"
#include "llslurl.h"
#include "lllayoutstack.h"
-#include "llagent.h"
#include "llnotificationsutil.h"
#include "lltoastnotifypanel.h"
#include "lltooltip.h"
@@ -61,7 +64,6 @@
#include "llurlaction.h"
#include "llviewercontrol.h"
#include "llviewerobjectlist.h"
-#include "llmutelist.h"
static LLDefaultChildRegistry::Register<LLChatHistory> r("chat_history");
@@ -187,6 +189,161 @@ public:
return false;
}
+ void banGroupMember(const LLUUID& participant_uuid)
+ {
+ LLUUID group_uuid = mSessionID;
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_uuid);
+ if (!gdatap)
+ {
+ // Not a group
+ return;
+ }
+
+ gdatap->banMemberById(participant_uuid);
+ }
+
+ bool canBanInGroup()
+ {
+ LLUUID group_uuid = mSessionID;
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_uuid);
+ if (!gdatap)
+ {
+ // Not a group
+ return false;
+ }
+
+ if (gAgent.hasPowerInGroup(group_uuid, GP_ROLE_REMOVE_MEMBER)
+ && gAgent.hasPowerInGroup(group_uuid, GP_GROUP_BAN_ACCESS))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ bool canBanGroupMember(const LLUUID& participant_uuid)
+ {
+ LLUUID group_uuid = mSessionID;
+ LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(group_uuid);
+ if (!gdatap)
+ {
+ // Not a group
+ return false;
+ }
+
+ if (gdatap->mPendingBanRequest)
+ {
+ return false;
+ }
+
+ if (gAgentID == getAvatarId())
+ {
+ //Don't ban self
+ return false;
+ }
+
+ if (gdatap->isRoleMemberDataComplete())
+ {
+ if (gdatap->mMembers.size())
+ {
+ LLGroupMgrGroupData::member_list_t::iterator mi = gdatap->mMembers.find(participant_uuid);
+ if (mi != gdatap->mMembers.end())
+ {
+ LLGroupMemberData* member_data = (*mi).second;
+ // Is the member an owner?
+ if (member_data && member_data->isInRole(gdatap->mOwnerRole))
+ {
+ return false;
+ }
+
+ if (gAgent.hasPowerInGroup(group_uuid, GP_ROLE_REMOVE_MEMBER)
+ && gAgent.hasPowerInGroup(group_uuid, GP_GROUP_BAN_ACCESS))
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ LLSpeakerMgr * speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
+ if (speaker_mgr)
+ {
+ LLSpeaker * speakerp = speaker_mgr->findSpeaker(participant_uuid).get();
+
+ if (speakerp
+ && gAgent.hasPowerInGroup(group_uuid, GP_ROLE_REMOVE_MEMBER)
+ && gAgent.hasPowerInGroup(group_uuid, GP_GROUP_BAN_ACCESS))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool isGroupModerator()
+ {
+ LLSpeakerMgr * speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
+ if (!speaker_mgr)
+ {
+ LL_WARNS() << "Speaker manager is missing" << LL_ENDL;
+ return false;
+ }
+
+ // Is session a group call/chat?
+ if(gAgent.isInGroup(mSessionID))
+ {
+ LLSpeaker * speakerp = speaker_mgr->findSpeaker(gAgentID).get();
+
+ // Is agent a moderator?
+ return speakerp && speakerp->mIsModerator;
+ }
+
+ return false;
+ }
+
+ bool canModerate(const std::string& userdata)
+ {
+ // only group moderators can perform actions related to this "enable callback"
+ if (!isGroupModerator() || gAgentID == getAvatarId())
+ {
+ return false;
+ }
+
+ LLSpeakerMgr * speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
+ if (!speaker_mgr)
+ {
+ return false;
+ }
+
+ LLSpeaker * speakerp = speaker_mgr->findSpeaker(getAvatarId()).get();
+ if (!speakerp)
+ {
+ return false;
+ }
+
+ bool voice_channel = speakerp->isInVoiceChannel();
+
+ if ("can_moderate_voice" == userdata)
+ {
+ return voice_channel;
+ }
+ else if ("can_mute" == userdata)
+ {
+ return voice_channel && (speakerp->mStatus != LLSpeaker::STATUS_MUTED);
+ }
+ else if ("can_unmute" == userdata)
+ {
+ return speakerp->mStatus == LLSpeaker::STATUS_MUTED;
+ }
+ else if ("can_allow_text_chat" == userdata)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
void onAvatarIconContextMenuItemClicked(const LLSD& userdata)
{
std::string level = userdata.asString();
@@ -245,11 +402,36 @@ public:
}
else if(level == "block_unblock")
{
- mute(getAvatarId(), LLMute::flagVoiceChat);
+ LLAvatarActions::toggleMute(getAvatarId(), LLMute::flagVoiceChat);
}
else if(level == "mute_unmute")
{
- mute(getAvatarId(), LLMute::flagTextChat);
+ LLAvatarActions::toggleMute(getAvatarId(), LLMute::flagTextChat);
+ }
+ else if(level == "toggle_allow_text_chat")
+ {
+ LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
+ speaker_mgr->toggleAllowTextChat(getAvatarId());
+ }
+ else if(level == "group_mute")
+ {
+ LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
+ if (speaker_mgr)
+ {
+ speaker_mgr->moderateVoiceParticipant(getAvatarId(), false);
+ }
+ }
+ else if(level == "group_unmute")
+ {
+ LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
+ if (speaker_mgr)
+ {
+ speaker_mgr->moderateVoiceParticipant(getAvatarId(), true);
+ }
+ }
+ else if(level == "ban_member")
+ {
+ banGroupMember(getAvatarId());
}
}
@@ -265,24 +447,69 @@ public:
{
return LLMuteList::getInstance()->isMuted(getAvatarId(), LLMute::flagTextChat);
}
+ else if (level == "is_allowed_text_chat")
+ {
+ if (gAgent.isInGroup(mSessionID))
+ {
+ LLIMSpeakerMgr* speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
+ const LLSpeaker * speakerp = speaker_mgr->findSpeaker(getAvatarId());
+
+ if (NULL != speakerp)
+ {
+ return !speakerp->mModeratorMutedText;
+ }
+ }
+ return false;
+ }
return false;
}
- void mute(const LLUUID& participant_id, U32 flags)
+ bool onAvatarIconContextMenuItemEnabled(const LLSD& userdata)
{
- BOOL is_muted = LLMuteList::getInstance()->isMuted(participant_id, flags);
- LLAvatarName av_name;
- LLAvatarNameCache::get(participant_id, &av_name);
- LLMute mute(participant_id, av_name.getUserName(), LLMute::AGENT);
+ std::string level = userdata.asString();
- if (!is_muted)
+ if (level == "can_allow_text_chat" || level == "can_mute" || level == "can_unmute")
{
- LLMuteList::getInstance()->add(mute, flags);
+ return canModerate(userdata);
}
- else
+ else if (level == "can_ban_member")
{
- LLMuteList::getInstance()->remove(mute, flags);
+ return canBanGroupMember(getAvatarId());
}
+ return false;
+ }
+
+ bool onAvatarIconContextMenuItemVisible(const LLSD& userdata)
+ {
+ std::string level = userdata.asString();
+
+ if (level == "show_mute")
+ {
+ LLSpeakerMgr * speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
+ if (speaker_mgr)
+ {
+ LLSpeaker * speakerp = speaker_mgr->findSpeaker(getAvatarId()).get();
+ if (speakerp)
+ {
+ return speakerp->isInVoiceChannel() && speakerp->mStatus != LLSpeaker::STATUS_MUTED;
+ }
+ }
+ return false;
+ }
+ else if (level == "show_unmute")
+ {
+ LLSpeakerMgr * speaker_mgr = LLIMModel::getInstance()->getSpeakerManager(mSessionID);
+ if (speaker_mgr)
+ {
+ LLSpeaker * speakerp = speaker_mgr->findSpeaker(getAvatarId()).get();
+ if (speakerp)
+ {
+ return speakerp->mStatus == LLSpeaker::STATUS_MUTED;
+ }
+ }
+ return false;
+ }
+ return false;
}
BOOL postBuild()
@@ -292,6 +519,8 @@ public:
registrar.add("AvatarIcon.Action", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemClicked, this, _2));
registrar_enable.add("AvatarIcon.Check", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemChecked, this, _2));
+ registrar_enable.add("AvatarIcon.Enable", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemEnabled, this, _2));
+ registrar_enable.add("AvatarIcon.Visible", boost::bind(&LLChatHistoryHeader::onAvatarIconContextMenuItemVisible, this, _2));
registrar.add("ObjectIcon.Action", boost::bind(&LLChatHistoryHeader::onObjectIconContextMenuItemClicked, this, _2));
registrar_enable.add("ObjectIcon.Visible", boost::bind(&LLChatHistoryHeader::onObjectIconContextMenuItemVisible, this, _2));
@@ -567,9 +796,14 @@ protected:
if(menu)
{
bool is_friend = LLAvatarActions::isFriend(mAvatarID);
+ bool is_group_session = gAgent.isInGroup(mSessionID);
menu->setItemEnabled("Add Friend", !is_friend);
menu->setItemEnabled("Remove Friend", is_friend);
+ menu->setItemVisible("Moderator Options Separator", is_group_session && isGroupModerator());
+ menu->setItemVisible("Moderator Options", is_group_session && isGroupModerator());
+ menu->setItemVisible("Group Ban Separator", is_group_session && canBanInGroup());
+ menu->setItemVisible("BanMember", is_group_session && canBanInGroup());
if(gAgentID == mAvatarID)
{
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index 3522932d03..333765f99f 100644
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -1150,11 +1150,11 @@ void LLFloaterIMContainer::doToParticipants(const std::string& command, uuid_vec
}
else if ("block_unblock" == command)
{
- toggleMute(userID, LLMute::flagVoiceChat);
+ LLAvatarActions::toggleMute(userID, LLMute::flagVoiceChat);
}
else if ("mute_unmute" == command)
{
- toggleMute(userID, LLMute::flagTextChat);
+ LLAvatarActions::toggleMute(userID, LLMute::flagTextChat);
}
else if ("selected" == command || "mute_all" == command || "unmute_all" == command)
{
@@ -2096,24 +2096,6 @@ void LLFloaterIMContainer::toggleAllowTextChat(const LLUUID& participant_uuid)
}
}
-void LLFloaterIMContainer::toggleMute(const LLUUID& participant_id, U32 flags)
-{
- BOOL is_muted = LLMuteList::getInstance()->isMuted(participant_id, flags);
-
- LLAvatarName av_name;
- LLAvatarNameCache::get(participant_id, &av_name);
- LLMute mute(participant_id, av_name.getUserName(), LLMute::AGENT);
-
- if (!is_muted)
- {
- LLMuteList::getInstance()->add(mute, flags);
- }
- else
- {
- LLMuteList::getInstance()->remove(mute, flags);
- }
-}
-
void LLFloaterIMContainer::openNearbyChat()
{
// If there's only one conversation in the container and that conversation is the nearby chat
diff --git a/indra/newview/llfloaterimcontainer.h b/indra/newview/llfloaterimcontainer.h
index 60cef83d9a..90fc0c2bdd 100644
--- a/indra/newview/llfloaterimcontainer.h
+++ b/indra/newview/llfloaterimcontainer.h
@@ -176,7 +176,6 @@ private:
void moderateVoiceAllParticipants(bool unmute);
void moderateVoiceParticipant(const LLUUID& avatar_id, bool unmute);
void toggleAllowTextChat(const LLUUID& participant_uuid);
- void toggleMute(const LLUUID& participant_id, U32 flags);
void banSelectedMember(const LLUUID& participant_uuid);
void openNearbyChat();
bool isParticipantListExpanded();
diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp
index e5fd126d53..7ee41140f0 100644
--- a/indra/newview/llinventorymodel.cpp
+++ b/indra/newview/llinventorymodel.cpp
@@ -799,22 +799,6 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id,
}
}
-U32 LLInventoryModel::getDescendentsCountRecursive(const LLUUID& id, U32 max_item_limit)
-{
- LLInventoryModel::cat_array_t cats;
- LLInventoryModel::item_array_t items;
- gInventory.collectDescendents(id, cats, items, LLInventoryModel::INCLUDE_TRASH);
-
- U32 items_found = items.size() + cats.size();
-
- for (U32 i = 0; i < cats.size() && items_found <= max_item_limit; ++i)
- {
- items_found += getDescendentsCountRecursive(cats[i]->getUUID(), max_item_limit - items_found);
- }
-
- return items_found;
-}
-
void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id, U32 mask)
{
const LLInventoryObject *obj = getObject(object_id);
@@ -3321,9 +3305,12 @@ void LLInventoryModel::emptyFolderType(const std::string notification, LLFolderT
LLSD args;
if(LLFolderType::FT_TRASH == preferred_type)
{
- static const U32 trash_max_capacity = gSavedSettings.getU32("InventoryTrashMaxCapacity");
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
const LLUUID trash_id = findCategoryUUIDForType(preferred_type);
- args["COUNT"] = (S32)getDescendentsCountRecursive(trash_id, trash_max_capacity);
+ gInventory.collectDescendents(trash_id, cats, items, LLInventoryModel::INCLUDE_TRASH); //All descendants
+ S32 item_count = items.size() + cats.size();
+ args["COUNT"] = item_count;
}
LLNotificationsUtil::add(notification, args, LLSD(),
boost::bind(&LLInventoryModel::callbackEmptyFolderType, this, _1, _2, preferred_type));
@@ -3433,9 +3420,20 @@ bool callback_preview_trash_folder(const LLSD& notification, const LLSD& respons
void LLInventoryModel::checkTrashOverflow()
{
- static const U32 trash_max_capacity = gSavedSettings.getU32("InventoryTrashMaxCapacity");
+ static LLCachedControl<U32> trash_max_capacity(gSavedSettings, "InventoryTrashMaxCapacity");
+
+ // Collect all descendants including those in subfolders.
+ //
+ // Note: Do we really need content of subfolders?
+ // This was made to prevent download of trash folder timeouting
+ // viewer and sub-folders are supposed to download independently.
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH);
- if (getDescendentsCountRecursive(trash_id, trash_max_capacity) >= trash_max_capacity)
+ gInventory.collectDescendents(trash_id, cats, items, LLInventoryModel::INCLUDE_TRASH);
+ S32 item_count = items.size() + cats.size();
+
+ if (item_count >= trash_max_capacity)
{
if (LLFloaterPreviewTrash::isVisible())
{
diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h
index c558c0803b..01e0ed7e9b 100644
--- a/indra/newview/llinventorymodel.h
+++ b/indra/newview/llinventorymodel.h
@@ -265,9 +265,6 @@ public:
// Follow parent chain to the top.
bool getObjectTopmostAncestor(const LLUUID& object_id, LLUUID& result) const;
-private:
- U32 getDescendentsCountRecursive(const LLUUID& id, U32 max_item_limit);
-
//--------------------------------------------------------------------
// Find
//--------------------------------------------------------------------
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 4b117941a0..f9c91312ee 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -1217,7 +1217,18 @@ void LLInventoryPanel::purgeSelectedItems()
const std::set<LLFolderViewItem*> inventory_selected = mFolderRoot.get()->getSelectionList();
if (inventory_selected.empty()) return;
LLSD args;
- args["COUNT"] = (S32)inventory_selected.size();
+ S32 count = inventory_selected.size();
+ for (std::set<LLFolderViewItem*>::const_iterator it = inventory_selected.begin(), end_it = inventory_selected.end();
+ it != end_it;
+ ++it)
+ {
+ LLUUID item_id = static_cast<LLFolderViewModelItemInventory*>((*it)->getViewModelItem())->getUUID();
+ LLInventoryModel::cat_array_t cats;
+ LLInventoryModel::item_array_t items;
+ gInventory.collectDescendents(item_id, cats, items, LLInventoryModel::INCLUDE_TRASH);
+ count += items.size() + cats.size();
+ }
+ args["COUNT"] = count;
LLNotificationsUtil::add("PurgeSelectedItems", args, LLSD(), boost::bind(&LLInventoryPanel::callbackPurgeSelectedItems, this, _1, _2));
}
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 507087d1ae..2dc219a769 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -1222,6 +1222,11 @@ void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_nam
const LLUUID& obj_id = (*obj_iter);
if(!highlight_offered_object(obj_id))
{
+ const LLViewerInventoryCategory *parent = gInventory.getFirstNondefaultParent(obj_id);
+ if (parent && (parent->getPreferredType() == LLFolderType::FT_TRASH))
+ {
+ gInventory.checkTrashOverflow();
+ }
continue;
}
diff --git a/indra/newview/skins/default/xui/en/menu_avatar_icon.xml b/indra/newview/skins/default/xui/en/menu_avatar_icon.xml
index 410caa7290..05ab4d35a0 100644
--- a/indra/newview/skins/default/xui/en/menu_avatar_icon.xml
+++ b/indra/newview/skins/default/xui/en/menu_avatar_icon.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
-<menu
+<toggleable_menu
height="101"
layout="topleft"
left="100"
@@ -109,5 +109,43 @@
name="Mute Text">
<on_click function="AvatarIcon.Action" parameter="mute_unmute" />
<on_check function="AvatarIcon.Check" parameter="is_muted" />
- </menu_item_check>
-</menu>
+ </menu_item_check>
+ <menu_item_separator layout="topleft" name="Moderator Options Separator"/>
+ <context_menu
+ label="Moderator Options"
+ layout="topleft"
+ name="Moderator Options">
+ <menu_item_check
+ label="Allow text chat"
+ layout="topleft"
+ name="AllowTextChat">
+ <on_check function="AvatarIcon.Check" parameter="is_allowed_text_chat" />
+ <on_click function="AvatarIcon.Action" parameter="toggle_allow_text_chat" />
+ <on_enable function="AvatarIcon.Enable" parameter="can_allow_text_chat" />
+ </menu_item_check>
+ <menu_item_call
+ label="Mute this participant"
+ layout="topleft"
+ name="ModerateVoiceMuteSelected">
+ <on_click function="AvatarIcon.Action" parameter="group_mute" />
+ <on_enable function="AvatarIcon.Enable" parameter="can_mute" />
+ <on_visible function="AvatarIcon.Visible" parameter="show_mute" />
+ </menu_item_call>
+ <menu_item_call
+ label="Unmute this participant"
+ layout="topleft"
+ name="ModerateVoiceUnMuteSelected">
+ <on_click function="AvatarIcon.Action" parameter="group_unmute" />
+ <on_enable function="AvatarIcon.Enable" parameter="can_unmute" />
+ <on_visible function="AvatarIcon.Visible" parameter="show_unmute" />
+ </menu_item_call>
+ </context_menu>
+ <menu_item_separator layout="topleft" name="Group Ban Separator"/>
+ <menu_item_call
+ label="Ban member"
+ layout="topleft"
+ name="BanMember">
+ <on_click function="AvatarIcon.Action" parameter="ban_member" />
+ <on_enable function="AvatarIcon.Enable" parameter="can_ban_member" />
+ </menu_item_call>
+</toggleable_menu>