From 77023234d350ff7d9434321b0e674c457b8c0333 Mon Sep 17 00:00:00 2001 From: PanteraPolnocy Date: Sun, 7 Dec 2025 20:21:46 +0100 Subject: [PATCH] Add support for pinning/unpinning groups in people panel and contacts floater Signed-off-by: PanteraPolnocy --- indra/newview/CMakeLists.txt | 2 + .../app_settings/settings_per_account.xml | 11 + indra/newview/fsfavoritegroups.cpp | 137 +++++++++++++ indra/newview/fsfavoritegroups.h | 62 ++++++ indra/newview/fsfloatercontacts.cpp | 18 ++ indra/newview/fsfloatercontacts.h | 2 + indra/newview/llgrouplist.cpp | 191 +++++++++++++++++- indra/newview/llgrouplist.h | 32 ++- indra/newview/llstartup.cpp | 5 + .../default/xui/en/floater_fs_contacts.xml | 6 + .../default/xui/en/menu_people_groups.xml | 26 +++ .../xui/en/panel_fs_contacts_groups.xml | 27 ++- .../xui/en/panel_group_list_separator.xml | 20 ++ .../default/xui/pl/floater_fs_contacts.xml | 2 + .../default/xui/pl/menu_people_groups.xml | 2 + .../xui/pl/panel_fs_contacts_groups.xml | 1 + 16 files changed, 527 insertions(+), 17 deletions(-) create mode 100644 indra/newview/fsfavoritegroups.cpp create mode 100644 indra/newview/fsfavoritegroups.h create mode 100644 indra/newview/skins/default/xui/en/panel_group_list_separator.xml diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 131c440a7e..1da8b911af 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -114,6 +114,7 @@ set(viewer_SOURCE_FILES fsdroptarget.cpp fsexportperms.cpp fsfloateraddtocontactset.cpp + fsfavoritegroups.cpp fsfloaterassetblacklist.cpp fsfloateravatarrendersettings.cpp fsfloaterblocklist.cpp @@ -956,6 +957,7 @@ set(viewer_HEADER_FILES fsdroptarget.h fsexportperms.h fsfloateraddtocontactset.h + fsfavoritegroups.h fsfloaterassetblacklist.h fsfloateravatarrendersettings.h fsfloaterblocklist.h diff --git a/indra/newview/app_settings/settings_per_account.xml b/indra/newview/app_settings/settings_per_account.xml index c95f78f244..bbd7a7015d 100644 --- a/indra/newview/app_settings/settings_per_account.xml +++ b/indra/newview/app_settings/settings_per_account.xml @@ -1374,6 +1374,17 @@ Value 0 + FSFavoriteGroups + + Comment + List of favorite/pinned group UUIDs + Persist + 1 + Type + LLSD + Value + + FSMaxSharedMaturity Comment diff --git a/indra/newview/fsfavoritegroups.cpp b/indra/newview/fsfavoritegroups.cpp new file mode 100644 index 0000000000..bea6900a79 --- /dev/null +++ b/indra/newview/fsfavoritegroups.cpp @@ -0,0 +1,137 @@ +/** + * @file fsfavoritegroups.cpp + * @brief Favorite groups storage management + * + * $LicenseInfo:firstyear=2025&license=viewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (C) 2025, The Phoenix Firestorm Project, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "fsfavoritegroups.h" + +#include "llagent.h" +#include "llviewercontrol.h" + +FSFavoriteGroups::FSFavoriteGroups() +{ +} + +FSFavoriteGroups::~FSFavoriteGroups() +{ + saveFavorites(); +} + +bool FSFavoriteGroups::isFavorite(const LLUUID& group_id) const +{ + return mFavoriteGroups.find(group_id) != mFavoriteGroups.end(); +} + +void FSFavoriteGroups::addFavorite(const LLUUID& group_id) +{ + if (group_id.isNull()) + { + return; + } + + if (mFavoriteGroups.insert(group_id).second) + { + saveFavorites(); + mFavoritesChangedSignal(); + } +} + +void FSFavoriteGroups::removeFavorite(const LLUUID& group_id) +{ + if (mFavoriteGroups.erase(group_id) > 0) + { + saveFavorites(); + mFavoritesChangedSignal(); + } +} + +void FSFavoriteGroups::toggleFavorite(const LLUUID& group_id) +{ + if (isFavorite(group_id)) + { + removeFavorite(group_id); + } + else + { + addFavorite(group_id); + } +} + +void FSFavoriteGroups::loadFavorites() +{ + mFavoriteGroups.clear(); + + LLSD favorites = gSavedPerAccountSettings.getLLSD("FSFavoriteGroups"); + + if (favorites.isArray()) + { + for (LLSD::array_const_iterator it = favorites.beginArray(); it != favorites.endArray(); ++it) + { + if (it->isUUID()) + { + mFavoriteGroups.insert(it->asUUID()); + } + } + } + + LL_INFOS("FavoriteGroups") << "Loaded " << mFavoriteGroups.size() << " favorite groups from per-account settings" << LL_ENDL; +} + +void FSFavoriteGroups::saveFavorites() +{ + + std::set stale_groups; + for (const auto& group_id : mFavoriteGroups) + { + if (!gAgent.isInGroup(group_id)) + { + stale_groups.insert(group_id); + } + } + + if (!stale_groups.empty()) + { + for (const auto& group_id : stale_groups) + { + mFavoriteGroups.erase(group_id); + } + LL_INFOS("FavoriteGroups") << "Removed " << stale_groups.size() << " stale group(s) from favorites (no longer a member)" << LL_ENDL; + } + + LLSD favorites_array = LLSD::emptyArray(); + + for (const auto& group_id : mFavoriteGroups) + { + favorites_array.append(group_id); + } + + gSavedPerAccountSettings.setLLSD("FSFavoriteGroups", favorites_array); + + LL_DEBUGS("FavoriteGroups") << "Saved " << mFavoriteGroups.size() << " favorite groups to per-account settings" << LL_ENDL; +} + + diff --git a/indra/newview/fsfavoritegroups.h b/indra/newview/fsfavoritegroups.h new file mode 100644 index 0000000000..7c75f34f42 --- /dev/null +++ b/indra/newview/fsfavoritegroups.h @@ -0,0 +1,62 @@ +/** + * @file fsfavoritegroups.h + * @brief Favorite groups storage management + * + * $LicenseInfo:firstyear=2025&license=viewerlgpl$ + * Phoenix Firestorm Viewer Source Code + * Copyright (C) 2025, The Phoenix Firestorm Project, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA + * http://www.firestormviewer.org + * $/LicenseInfo$ + */ + +#ifndef FS_FAVORITEGROUPS_H +#define FS_FAVORITEGROUPS_H + +#include "llsingleton.h" +#include "lluuid.h" +#include +#include + +class FSFavoriteGroups : public LLSingleton +{ + LLSINGLETON(FSFavoriteGroups); + ~FSFavoriteGroups(); + +public: + bool isFavorite(const LLUUID& group_id) const; + void addFavorite(const LLUUID& group_id); + void removeFavorite(const LLUUID& group_id); + void toggleFavorite(const LLUUID& group_id); + const std::set& getFavorites() const { return mFavoriteGroups; } + bool hasFavorites() const { return !mFavoriteGroups.empty(); } + void loadFavorites(); + void saveFavorites(); + + typedef boost::signals2::signal favorites_changed_signal_t; + boost::signals2::connection setFavoritesChangedCallback(const favorites_changed_signal_t::slot_type& cb) + { + return mFavoritesChangedSignal.connect(cb); + } + +private: + std::set mFavoriteGroups; + favorites_changed_signal_t mFavoritesChangedSignal; +}; + +#endif // FS_FAVORITEGROUPS_H diff --git a/indra/newview/fsfloatercontacts.cpp b/indra/newview/fsfloatercontacts.cpp index f976f0218b..122d8f44a2 100644 --- a/indra/newview/fsfloatercontacts.cpp +++ b/indra/newview/fsfloatercontacts.cpp @@ -31,6 +31,7 @@ #include "fscommon.h" #include "fscontactsfriendsmenu.h" +#include "fsfavoritegroups.h" #include "fsfloaterimcontainer.h" #include "fsscrolllistctrl.h" #include "llagent.h" @@ -147,6 +148,7 @@ bool FSFloaterContacts::postBuild() mGroupsChatBtn = mGroupsTab->getChild("chat_btn"); mGroupsInfoBtn = mGroupsTab->getChild("info_btn"); mGroupsActivateBtn = mGroupsTab->getChild("activate_btn"); + mGroupsFavoriteBtn = mGroupsTab->getChild("favorite_btn"); mGroupsLeaveBtn = mGroupsTab->getChild("leave_btn"); mGroupsCreateBtn = mGroupsTab->getChild("create_btn"); mGroupsSearchBtn = mGroupsTab->getChild("search_btn"); @@ -156,6 +158,7 @@ bool FSFloaterContacts::postBuild() mGroupsChatBtn->setCommitCallback(boost::bind(&FSFloaterContacts::onGroupChatButtonClicked, this)); mGroupsInfoBtn->setCommitCallback(boost::bind(&FSFloaterContacts::onGroupInfoButtonClicked, this)); mGroupsActivateBtn->setCommitCallback(boost::bind(&FSFloaterContacts::onGroupActivateButtonClicked, this)); + mGroupsFavoriteBtn->setCommitCallback(boost::bind(&FSFloaterContacts::onGroupFavoriteButtonClicked, this)); mGroupsLeaveBtn->setCommitCallback(boost::bind(&FSFloaterContacts::onGroupLeaveButtonClicked, this)); mGroupsCreateBtn->setCommitCallback(boost::bind(&FSFloaterContacts::onGroupCreateButtonClicked, this)); mGroupsSearchBtn->setCommitCallback(boost::bind(&FSFloaterContacts::onGroupSearchButtonClicked, this)); @@ -247,6 +250,12 @@ void FSFloaterContacts::updateGroupButtons() mGroupsLeaveBtn->setEnabled(isGroup); mGroupsCreateBtn->setEnabled((!gMaxAgentGroups) || (gAgent.mGroups.size() < gMaxAgentGroups)); mGroupsInviteBtn->setEnabled(isGroup && gAgent.hasPowerInGroup(groupId, GP_MEMBER_INVITE)); + mGroupsFavoriteBtn->setEnabled(isGroup); + if (isGroup) + { + bool is_favorite = FSFavoriteGroups::getInstance()->isFavorite(groupId); + mGroupsFavoriteBtn->setLabel(is_favorite ? getString("unfavorite_label") : getString("favorite_label")); + } } void FSFloaterContacts::onOpen(const LLSD& key) @@ -432,6 +441,15 @@ void FSFloaterContacts::onGroupActivateButtonClicked() LLGroupActions::activate(mGroupList->getSelectedUUID()); } +void FSFloaterContacts::onGroupFavoriteButtonClicked() +{ + if (LLUUID group_id = getCurrentItemID(); group_id.notNull()) + { + FSFavoriteGroups::getInstance()->toggleFavorite(group_id); + updateGroupButtons(); + } +} + void FSFloaterContacts::onGroupLeaveButtonClicked() { if (LLUUID group_id = getCurrentItemID(); group_id.notNull()) diff --git a/indra/newview/fsfloatercontacts.h b/indra/newview/fsfloatercontacts.h index 949769d0e2..c180582e5d 100644 --- a/indra/newview/fsfloatercontacts.h +++ b/indra/newview/fsfloatercontacts.h @@ -141,6 +141,7 @@ private: void onGroupChatButtonClicked(); void onGroupInfoButtonClicked(); void onGroupActivateButtonClicked(); + void onGroupFavoriteButtonClicked(); void onGroupLeaveButtonClicked(); void onGroupCreateButtonClicked(); void onGroupSearchButtonClicked(); @@ -167,6 +168,7 @@ private: LLButton* mGroupsChatBtn{ nullptr }; LLButton* mGroupsInfoBtn{ nullptr }; LLButton* mGroupsActivateBtn{ nullptr }; + LLButton* mGroupsFavoriteBtn{ nullptr }; LLButton* mGroupsLeaveBtn{ nullptr }; LLButton* mGroupsCreateBtn{ nullptr }; LLButton* mGroupsSearchBtn{ nullptr }; diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp index 774ff5b6c4..85e4aefa0f 100644 --- a/indra/newview/llgrouplist.cpp +++ b/indra/newview/llgrouplist.cpp @@ -46,6 +46,7 @@ // [RLVa:KB] - Checked: RLVa-2.0.3 #include "rlvactions.h" // [/RLVa:KB] +#include "fsfavoritegroups.h" // Group favorites / pinning #include "llslurl.h" #include "llurlaction.h" @@ -59,8 +60,37 @@ public: /** Returns true if item1 < item2, false otherwise */ /*virtual*/ bool compare(const LLPanel* item1, const LLPanel* item2) const { - std::string name1 = static_cast(item1)->getGroupName(); - std::string name2 = static_cast(item2)->getGroupName(); + // Group favorites / pinning + // std::string name1 = static_cast(item1)->getGroupName(); + // std::string name2 = static_cast(item2)->getGroupName(); + + const LLGroupListItem* group_item1 = dynamic_cast(item1); + const LLGroupListItem* group_item2 = dynamic_cast(item2); + + if (!group_item1 || !group_item2) + { + if (!group_item1 && group_item2) + { + return group_item2->isFavorite() ? false : true; + } + if (group_item1 && !group_item2) + { + return group_item1->isFavorite() ? true : false; + } + return false; + } + + bool fav1 = group_item1->isFavorite(); + bool fav2 = group_item2->isFavorite(); + + if (fav1 != fav2) + { + return fav1 > fav2; + } + + std::string name1 = group_item1->getGroupName(); + std::string name2 = group_item2->getGroupName(); + // LLStringUtil::toUpper(name1); LLStringUtil::toUpper(name2); @@ -76,11 +106,22 @@ public: /*virtual*/ bool compare(const LLPanel* item1, const LLPanel* item2) const { - const LLGroupListItem* group_item1 = static_cast(item1); + // Group favorites / pinning + const LLGroupListItem* group_item1 = dynamic_cast(item1); + const LLGroupListItem* group_item2 = dynamic_cast(item2); + if (!group_item1 || !group_item2) + { + // Sorting doesn't matter, as we hit a separator that shouldn't be visible in this view + return false; + } + + // const LLGroupListItem* group_item1 = static_cast(item1); + // + std::string name1 = group_item1->getGroupName(); bool item1_shared = gAgent.isInGroup(group_item1->getGroupID(), true); - const LLGroupListItem* group_item2 = static_cast(item2); + // const LLGroupListItem* group_item2 = static_cast(item2); - Group favorites / pinning std::string name2 = group_item2->getGroupName(); bool item2_shared = gAgent.isInGroup(group_item2->getGroupID(), true); @@ -134,6 +175,12 @@ LLGroupList::~LLGroupList() { if (mForAgent) gAgent.removeListener(this); if (mContextMenuHandle.get()) mContextMenuHandle.get()->die(); + // Group favorites / pinning + if (mFavoritesChangedConnection.connected()) + { + mFavoritesChangedConnection.disconnect(); + } + // } void LLGroupList::enableForAgent(bool show_icons) @@ -152,6 +199,11 @@ void LLGroupList::enableForAgent(bool show_icons) registrar.add("People.Groups.Action", boost::bind(&LLGroupList::onContextMenuItemClick, this, _2)); enable_registrar.add("People.Groups.Enable", boost::bind(&LLGroupList::onContextMenuItemEnable, this, _2)); + // Group favorites / pinning + mFavoritesChangedConnection = FSFavoriteGroups::getInstance()->setFavoritesChangedCallback(boost::bind(&LLGroupList::onFavoritesChanged, this)); + enable_registrar.add("People.Groups.Visible", boost::bind(&LLGroupList::onContextMenuItemVisible, this, _2)); + // + LLToggleableMenu* context_menu = LLUICtrlFactory::getInstance()->createFromFile("menu_people_groups.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); if(context_menu) @@ -174,6 +226,13 @@ bool LLGroupList::handleRightMouseDown(S32 x, S32 y, MASK mask) if (mForAgent) { + // Group favorites / pinning + LLPanel* selected_item = getSelectedItem(); + if (dynamic_cast(selected_item)) + { + return handled; + } + // LLToggleableMenu* context_menu = mContextMenuHandle.get(); if (context_menu && size() > 0) { @@ -234,24 +293,53 @@ void LLGroupList::refresh() clear(); + // Group favorites / pinning + bool has_favorites = false; + bool has_non_favorites = false; + // + for(S32 i = 0; i < count; ++i) { id = gAgent.mGroups.at(i).mID; const LLGroupData& group_data = gAgent.mGroups.at(i); if (have_filter && !findInsensitive(group_data.mName, mNameFilter)) continue; - addNewItem(id, group_data.mName, group_data.mInsigniaID, ADD_BOTTOM, group_data.mListInProfile); + + // Group favorites / pinning + // addNewItem(id, group_data.mName, group_data.mInsigniaID, ADD_BOTTOM, group_data.mListInProfile); + bool is_favorite = FSFavoriteGroups::getInstance()->isFavorite(id); + if (is_favorite) + { + has_favorites = true; + } + else + { + has_non_favorites = true; + } + addNewItem(id, group_data.mName, group_data.mInsigniaID, ADD_BOTTOM, group_data.mListInProfile, is_favorite); + // + } // Sort the list. sort(); + // Group favorites / pinning + if (has_favorites && has_non_favorites && !have_filter) + { + addFavoritesSeparator(); + } + // + // Add "none" to list at top if filter not set (what's the point of filtering "none"?). // but only if some real groups exists. EXT-4838 if (!have_filter && count > 0 && mShowNone) { std::string loc_none = LLTrans::getString("GroupsNone"); - addNewItem(LLUUID::null, loc_none, LLUUID::null, ADD_TOP); + // Group favorites / pinning + // addNewItem(LLUUID::null, loc_none, LLUUID::null, ADD_TOP); + addNewItem(LLUUID::null, loc_none, LLUUID::null, ADD_TOP, true, false); + // } selectItemByUUID(highlight_id); @@ -298,13 +386,17 @@ void LLGroupList::setGroups(const std::map< std::string,LLUUID> group_list) // PRIVATE Section ////////////////////////////////////////////////////////////////////////// -void LLGroupList::addNewItem(const LLUUID& id, const std::string& name, const LLUUID& icon_id, EAddPosition pos, bool visible_in_profile) +// Group favorites / pinning +// void LLGroupList::addNewItem(const LLUUID& id, const std::string& name, const LLUUID& icon_id, EAddPosition pos, bool visible_in_profile) +void LLGroupList::addNewItem(const LLUUID& id, const std::string& name, const LLUUID& icon_id, EAddPosition pos, bool visible_in_profile, bool is_favorite) +// { LLGroupListItem* item = new LLGroupListItem(mForAgent, mShowIcons); item->setGroupID(id); item->setName(name, mNameFilter); item->setGroupIconID(icon_id); + item->setFavorite(is_favorite); // Group favorites / pinning item->getChildView("info_btn")->setVisible( false); item->getChildView("profile_btn")->setVisible( false); @@ -390,6 +482,16 @@ bool LLGroupList::onContextMenuItemClick(const LLSD& userdata) LLUrlAction::copyURLToClipboard(LLSLURL("group", selected_group, "about").getSLURLString()); } // + // Group favorites / pinning + else if (action == "favorite") + { + FSFavoriteGroups::getInstance()->addFavorite(selected_group); + } + else if (action == "unfavorite") + { + FSFavoriteGroups::getInstance()->removeFavorite(selected_group); + } + // return true; } @@ -412,9 +514,84 @@ bool LLGroupList::onContextMenuItemEnable(const LLSD& userdata) if (userdata.asString() == "call") return real_group_selected && LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking(); + // Group favorites / pinning + if (userdata.asString() == "favorite" || userdata.asString() == "unfavorite") + return real_group_selected; // Just in case + // + return real_group_selected; } +// Group favorites / pinning +bool LLGroupList::onContextMenuItemVisible(const LLSD& userdata) +{ + std::string action = userdata.asString(); + LLUUID selected_group_id = getSelectedUUID(); + + if (action == "favorite") + { + return selected_group_id.notNull() && !FSFavoriteGroups::getInstance()->isFavorite(selected_group_id); + } + else if (action == "unfavorite") + { + return selected_group_id.notNull() && FSFavoriteGroups::getInstance()->isFavorite(selected_group_id); + } + + return true; +} + +void LLGroupList::onFavoritesChanged() +{ + setDirty(); +} + +void LLGroupList::refreshFavorites() +{ + setDirty(); +} + +void LLGroupList::addFavoritesSeparator() +{ + // Find the position to insert the separator (after the last favorite) + std::vector items; + getItems(items); + + // Count favorite items to find where separator should go + S32 favorite_count = 0; + for (auto* panel : items) + { + LLGroupListItem* item = dynamic_cast(panel); + if (item && item->isFavorite()) + { + ++favorite_count; + } + } + + if (favorite_count > 0) + { + LLGroupListSeparator* separator = new LLGroupListSeparator(); + static const LLUUID SEPARATOR_UUID("00000000-0000-0000-0000-000000000001"); + addItem(separator, SEPARATOR_UUID, ADD_BOTTOM, false); + sort(); + } +} + +/************************************************************************/ +/* LLGroupListSeparator implementation */ +/************************************************************************/ + +LLGroupListSeparator::LLGroupListSeparator() + : LLPanel() +{ + buildFromFile("panel_group_list_separator.xml"); +} + +bool LLGroupListSeparator::postBuild() +{ + return true; +} +// + /************************************************************************/ /* LLGroupListItem implementation */ /************************************************************************/ diff --git a/indra/newview/llgrouplist.h b/indra/newview/llgrouplist.h index 19d4e82a93..02966c0c2e 100644 --- a/indra/newview/llgrouplist.h +++ b/indra/newview/llgrouplist.h @@ -37,6 +37,8 @@ #include "llgroupmgr.h" +#include // Group favorites / pinning + /** * Auto-updating list of agent groups. * @@ -72,14 +74,22 @@ public: LLToggleableMenu* getContextMenu() const { return mContextMenuHandle.get(); } + void refreshFavorites(); // Group favorites / pinning + private: void setDirty(bool val = true) { mDirty = val; } void refresh(); - void addNewItem(const LLUUID& id, const std::string& name, const LLUUID& icon_id, EAddPosition pos = ADD_BOTTOM, bool visible_in_profile = true); +// Group favorites / pinning + // void addNewItem(const LLUUID& id, const std::string& name, const LLUUID& icon_id, EAddPosition pos = ADD_BOTTOM, bool visible_in_profile = true); + void addNewItem(const LLUUID& id, const std::string& name, const LLUUID& icon_id, EAddPosition pos = ADD_BOTTOM, bool visible_in_profile = true, bool is_favorite = false); + void addFavoritesSeparator(); + void onFavoritesChanged(); +// bool handleEvent(LLPointer event, const LLSD& userdata); // called on agent group list changes bool onContextMenuItemClick(const LLSD& userdata); bool onContextMenuItemEnable(const LLSD& userdata); + bool onContextMenuItemVisible(const LLSD& userdata); // Group favorites / pinning LLHandle mContextMenuHandle; @@ -91,12 +101,29 @@ private: bool mShowNone; typedef std::map< std::string,LLUUID> group_map_t; group_map_t mGroups; + + boost::signals2::connection mFavoritesChangedConnection; // Group favorites / pinning }; class LLButton; class LLGroupIconCtrl; class LLTextBox; +// Group favorites / pinning +class LLGroupListSeparator : public LLPanel +{ +public: + LLGroupListSeparator(); + /*virtual*/ bool postBuild(); + // Ignore all mouse interactions on the separator + /*virtual*/ bool handleMouseDown(S32 x, S32 y, MASK mask) { return true; } + /*virtual*/ bool handleMouseUp(S32 x, S32 y, MASK mask) { return true; } + /*virtual*/ bool handleRightMouseDown(S32 x, S32 y, MASK mask) { return true; } + /*virtual*/ bool handleRightMouseUp(S32 x, S32 y, MASK mask) { return true; } + /*virtual*/ bool handleDoubleClick(S32 x, S32 y, MASK mask) { return true; } +}; +// + class LLGroupListItem : public LLPanel , public LLGroupMgrObserver { @@ -110,11 +137,13 @@ public: const LLUUID& getGroupID() const { return mGroupID; } const std::string& getGroupName() const { return mGroupName; } + bool isFavorite() const { return mIsFavorite; } // Group favorites / pinning void setName(const std::string& name, const std::string& highlight = LLStringUtil::null); void setGroupID(const LLUUID& group_id); void setGroupIconID(const LLUUID& group_icon_id); void setGroupIconVisible(bool visible); + void setFavorite(bool favorite) { mIsFavorite = favorite; } // Group favorites / pinning virtual void changed(LLGroupChange gc); @@ -137,6 +166,7 @@ private: std::string mGroupName; bool mForAgent; + bool mIsFavorite{ false }; // Group favorites / pinning LLStyle::Params mGroupNameStyle; S32 mIconWidth; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 1df85c25b0..be5d645850 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -233,6 +233,7 @@ #include "fscommon.h" #include "fscorehttputil.h" #include "fsdata.h" +#include "fsfavoritegroups.h" // Group favorites / pinning #include "fsfloatercontacts.h" #include "fsfloaterimcontainer.h" #include "fsfloaternearbychat.h" @@ -3315,6 +3316,10 @@ bool idle_startup() // Clean up the userauth stuff. // LLUserAuth::getInstance()->reset(); + // Group favorites / pinning + FSFavoriteGroups::getInstance()->loadFavorites(); + // + LLStartUp::setStartupState( STATE_STARTED ); do_startup_frame(); diff --git a/indra/newview/skins/default/xui/en/floater_fs_contacts.xml b/indra/newview/skins/default/xui/en/floater_fs_contacts.xml index f375e6f102..27ff4d6247 100644 --- a/indra/newview/skins/default/xui/en/floater_fs_contacts.xml +++ b/indra/newview/skins/default/xui/en/floater_fs_contacts.xml @@ -24,6 +24,12 @@ + + + + + + + + + + + + +