Discord rich presence support

master
Liny 2019-09-10 04:24:02 -07:00
parent 768cced8fb
commit 1c8be4e323
17 changed files with 1164 additions and 0 deletions

View File

@ -237,6 +237,58 @@
</map>
</map>
</map>
<key>discord-rpc</key>
<map>
<key>copyright</key>
<string>Copyright 2019 Discord, Inc.</string>
<key>description</key>
<string>C++ library to interface with Discord's API</string>
<key>license</key>
<string>MIT</string>
<key>license_file</key>
<string>LICENSES/discord-rpc.txt</string>
<key>name</key>
<string>discord-rpc</string>
<key>platforms</key>
<map>
<key>windows</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>b760b4f3ab7794a897cf7f464d92e587</string>
<key>url</key>
<uri>http://downloads.phoenixviewer.com/discord_rpc-3.4.0-windows-192510505.tar.bz2</uri>
</map>
<key>name</key>
<string>windows</string>
</map>
<key>linux64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>756c1dd3dddf218352b83b54db400056</string>
<key>url</key>
<uri>http://downloads.phoenixviewer.com/discord_rpc-3.4.0-darwin64-192522358.tar.bz2</uri>
</map>
<key>name</key>
<string>linux64</string>
</map>
<key>darwin64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>3bc297a0fa47094bb52d361f80186387</string>
<key>url</key>
<uri>http://downloads.phoenixviewer.com/discord_rpc-3.4.0-linux64-192531056.tar.bz2</uri>
</map>
<key>name</key>
<string>darwin64</string>
</map>
</map>
</map>
<key>SDL</key>
<map>
<key>copyright</key>

View File

@ -22,6 +22,7 @@ set(cmake_SOURCE_FILES
Copy3rdPartyLibs.cmake
DBusGlib.cmake
DeploySharedLibs.cmake
Discord.cmake # <FS:LO> Discord rich presence
DirectX.cmake
DragDrop.cmake
EXPAT.cmake

18
indra/cmake/Discord.cmake Normal file
View File

@ -0,0 +1,18 @@
# -*- cmake -*-
include(Prebuilt)
use_prebuilt_binary(discord-rpc)
set(DISCORD_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/discord-rpc)
if (ADDRESS_SIZE EQUAL 32 AND WINDOWS)
set(DISCORD_LIBRARY discord-rpc)
elseif (WINDOWS)
set(DISCORD_LIBRARY discord-rpc_x64)
elseif (LINUX || DARWIN)
set(DISCORD_LIBRARY libdiscord-rpc)
endif (ADDRESS_SIZE EQUAL 32 AND WINDOWS)
if (DISCORD_API_KEY)
add_definitions( -DDISCORD_API_KEY=\"${DISCORD_API_KEY}\")
endif (DISCORD_API_KEY)

View File

@ -60,6 +60,7 @@ include(URIPARSER)
include(Growl)
include(ColladaDom)
include(jemalloc)
include(Discord)
# <FS:ND> if using ndPhysicsstub this variable will be unset, we don't need to build any stub code viewer side in that case
if( LLPHYSICSEXTENSIONS_SRC_DIR )
@ -1792,6 +1793,11 @@ if (WINDOWS)
# [FS]
)
#<FS:LO> Discord rich presence
LIST(APPEND viewer_HEADER_FILES fsfloaterdiscord.h fsdiscordconnect.h)
LIST(APPEND viewer_SOURCE_FILES fsfloaterdiscord.cpp fsdiscordconnect.cpp)
#</FS:LO>
# precompiled header configuration
# llviewerprecompiledheaders.cpp generates
# the .pch file.
@ -2432,6 +2438,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
${LLPHYSICSEXTENSIONS_LIBRARIES}
${LLAPPEARANCE_LIBRARIES}
${GROWL_LIBRARY}
${DISCORD_LIBRARY}
)
if (BUGSPLAT_DB)

View File

@ -633,4 +633,14 @@
execute_function="Tools.StopAllAnimations"
execute_parameters="stop"
/>
<command name="discord"
available_in_toybox="true"
icon="Command_Discord_Icon"
label_ref="Command_Discord_Label"
tooltip_ref="Command_Discord_Tooltip"
execute_function="Floater.Toggle"
execute_parameters="fs_discord"
is_running_function="Floater.IsOpen"
is_running_parameters="fs_discord"
/>
</commands>

View File

@ -1224,5 +1224,38 @@
<key>Value</key>
<integer>1</integer>
</map>
<key>FSEnableDiscordIntegration</key>
<map>
<key>Comment</key>
<string>If enabled, well allow Firestorm to connect to discord if open and share location data with. Default (false)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSMaxSharedMaturity</key>
<map>
<key>Comment</key>
<string>Max maturity rating to share with Discord</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>13</integer>
</map>
<key>FSBlacklistedRegionNames</key>
<map>
<key>Comment</key>
<string>List of region names to never share with Discord</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>LLSD</string>
<key>Value</key>
<array></array>
</map>
</map>
</llsd>

View File

@ -0,0 +1,332 @@
/**
* @file fsdiscordconnect.cpp
* @brief Connection to Discord
* @author liny@pinkfox.xyz
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
* Phoenix Firestorm Viewer Source Code
* Copyright (C) 2019 Liny Odell @ Second Life
*
* 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
*/
#include "llviewerprecompiledheaders.h"
#include "fsdiscordconnect.h"
#include "llagent.h"
#include "llcallingcard.h" // for LLAvatarTracker
#include "llcommandhandler.h"
#include "llnotificationsutil.h"
#include "lltrans.h"
#include "llevents.h"
#include "llviewerregion.h"
#include "llavatarnamecache.h"
#include "llregioninfomodel.h"
#include "rlvactions.h"
#include "rlvhandler.h"
#include "llfloaterreg.h"
#include "discord-rpc\discord_rpc.h"
#include "boost/algorithm/string/case_conv.hpp"
#ifndef DISCORD_API_KEY
#define DISCORD_API_KEY ""
#endif
boost::scoped_ptr<LLEventPump> FSDiscordConnect::sStateWatcher(new LLEventStream("DiscordConnectState"));
boost::scoped_ptr<LLEventPump> FSDiscordConnect::sInfoWatcher(new LLEventStream("DiscordConnectInfo"));
// Returns false when the file exists and has not our UUID
// Or, put simply, returns true if someone else is using it
bool FSDiscordConnect::checkMarkerFile()
{
if (!LLFile::isfile(mMarkerFilename))
{
return false;
}
LLUUID fileID;
llifstream file(mMarkerFilename);
file >> fileID;
if ((fileID == gAgentID) || fileID.isNull())
{
return false;
}
return true;
}
void FSDiscordConnect::setMarkerFile()
{
//LLFile file = LLFile::fopen(mMarkerFilename, "w");
if (!checkMarkerFile())
{
return; // dont over-write another instances file
}
llofstream file = llofstream(mMarkerFilename.c_str());
file << gAgentID << std::endl;
file.close();
}
void FSDiscordConnect::clearMarkerFile()
{
if (!checkMarkerFile())
{
return; // dont remove another instances file
}
LLFile::remove(mMarkerFilename);
}
void handleDiscordReady(const DiscordUser *request)
{
LLSD info;
info["name"] = request->username;
FSDiscordConnect::getInstance()->storeInfo(info);
FSDiscordConnect::getInstance()->setConnectionState(FSDiscordConnect::DISCORD_CONNECTED);
}
void handleDiscordError(int errorCode, const char* message)
{
LL_WARNS("DiscordConnect") << "Discord error, errorCode: \"" << errorCode << "\", message: \"" << message << "\"" << LL_ENDL;
}
void handleDiscordDisconnected(int errorCode, const char* message)
{
LL_INFOS("DiscordConnect") << "Discord disconnected, errorCode: \"" << errorCode << "\", message: \"" << message << "\"" << LL_ENDL;
FSDiscordConnect::getInstance()->setConnectionState(FSDiscordConnect::DISCORD_NOT_CONNECTED);
}
///////////////////////////////////////////////////////////////////////////////
//
void FSDiscordConnect::discordConnectCoro()
{
DiscordEventHandlers handlers;
memset(&handlers, 0, sizeof(handlers));
handlers.ready = handleDiscordReady;
handlers.errored = handleDiscordError;
handlers.disconnected = handleDiscordDisconnected;
//TODO: Get this working and sending TPs
/*handlers.joinGame = handleDiscordJoinGame;
handlers.spectateGame = handleDiscordSpectateGame;
handlers.joinRequest = handleDiscordJoinRequest;*/
Discord_Initialize(DISCORD_API_KEY, &handlers, 1, "");
}
///////////////////////////////////////////////////////////////////////////////
//
void FSDiscordConnect::discordDisconnectCoro()
{
Discord_Shutdown();
setConnectionState(FSDiscordConnect::DISCORD_NOT_CONNECTED);
}
///////////////////////////////////////////////////////////////////////////////
//
void FSDiscordConnect::discordConnectedCoro(bool autoConnect)
{
if (autoConnect)
{
setConnectionState(FSDiscordConnect::DISCORD_CONNECTION_IN_PROGRESS);
if (!checkMarkerFile())
{
connectToDiscord();
}
else
{
setConnectionState(FSDiscordConnect::DISCORD_CONNECTION_FAILED);
}
}
}
bool isRegionVisible(LLViewerRegion* region)
{
U8 rating = region->getSimAccess();
bool visible = true;
if (!(rating <= gSavedPerAccountSettings.getU32("FSMaxSharedMaturity")))
{
visible = false;
}
else
{
std::string name = region->getName();
LLSD list = gSavedPerAccountSettings.getLLSD("FSBlacklistedRegionNames");
for (LLSD::array_const_iterator iter = list.beginArray();
iter != list.endArray();
iter++)
{
if (boost::algorithm::to_lower_copy((*iter).asString()) == boost::algorithm::to_lower_copy(name))
{
visible = false;
break;
}
}
}
return visible;
}
void FSDiscordConnect::updateRichPresence()
{
LLViewerRegion * region = gAgent.getRegion();
if (!isConnected() || !region)
{
return;
}
std::string region_name;
if (RlvActions::canShowLocation() && isRegionVisible(region))
{
region_name = gAgent.getRegion()->getName();
region_name += " ";
LLVector3 pos = gAgent.getPositionAgent();
region_name += llformat("(%.0f, %.0f, %.0f)", pos.mV[0], pos.mV[1], pos.mV[2]);
}
else
{
region_name = RlvStrings::getString(RLV_STRING_HIDDEN_REGION);
}
DiscordRichPresence discordPresence;
memset(&discordPresence, 0, sizeof(discordPresence));
discordPresence.state = region_name.c_str();
LLAvatarName av_name;
std::string name;
if (RlvActions::canShowName(RlvActions::SNC_DEFAULT, gAgentID))
{
if (LLAvatarNameCache::get(gAgentID, &av_name))
{
name = av_name.getCompleteName(true, true);
}
else
{
name = gAgentUsername;
}
}
else
{
name = RlvStrings::getAnonym(av_name);
}
discordPresence.details = name.c_str();
discordPresence.largeImageKey = "secondlife_512";
discordPresence.largeImageText = "Second Life";
discordPresence.smallImageKey = "firestorm_512";
//const char* appname = std::string("via " + APP_NAME).c_str(); // No idea why this doesnt work, but discord receives random data from somewhere in the programs address space and not the text that it should
discordPresence.smallImageText = "via Firestorm"; // I hate to hardcode the word "Firestorm" cause of the above global, but this way works
discordPresence.partyId = gAgent.getRegion()->getRegionID().asString().c_str();
discordPresence.partySize = gAgent.getRegion()->mMapAvatars.size();
discordPresence.partyMax = LLRegionInfoModel::instance().mAgentLimit;
Discord_UpdatePresence(&discordPresence);
}
///////////////////////////////////////////////////////////////////////////////
//
FSDiscordConnect::FSDiscordConnect()
: mConnectionState(DISCORD_NOT_CONNECTED),
mConnected(false),
mInfo(),
mRefreshInfo(false)
{
mMarkerFilename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "discord_in_use_marker");
LLEventPumps::instance().obtain("mainloop").listen("FSDiscordConnect", boost::bind(&FSDiscordConnect::Tick, this, _1));
}
FSDiscordConnect::~FSDiscordConnect()
{
disconnectFromDiscord();
}
void FSDiscordConnect::connectToDiscord()
{
LLCoros::instance().launch("FSDiscordConnect::discordConnectCoro",
boost::bind(&FSDiscordConnect::discordConnectCoro, this));
}
void FSDiscordConnect::disconnectFromDiscord()
{
setConnectionState(FSDiscordConnect::DISCORD_DISCONNECTING);
LLCoros::instance().launch("FSDiscordConnect::discordDisconnectCoro",
boost::bind(&FSDiscordConnect::discordDisconnectCoro, this));
}
void FSDiscordConnect::checkConnectionToDiscord(bool auto_connect)
{
LLCoros::instance().launch("FSDiscordConnect::discordConnectedCoro",
boost::bind(&FSDiscordConnect::discordConnectedCoro, this, auto_connect));
}
bool FSDiscordConnect::Tick(const LLSD&)
{
Discord_RunCallbacks();
updateRichPresence();
return false;
}
void FSDiscordConnect::storeInfo(const LLSD& info)
{
mInfo = info;
mRefreshInfo = false;
sInfoWatcher->post(info);
}
const LLSD& FSDiscordConnect::getInfo() const
{
return mInfo;
}
void FSDiscordConnect::clearInfo()
{
mInfo = LLSD();
}
void FSDiscordConnect::setConnectionState(FSDiscordConnect::EConnectionState connection_state)
{
if(connection_state == DISCORD_CONNECTED)
{
setMarkerFile();
setConnected(true);
}
else if(connection_state == DISCORD_NOT_CONNECTED)
{
clearMarkerFile();
setConnected(false);
}
if (mConnectionState != connection_state)
{
// set the connection state before notifying watchers
mConnectionState = connection_state;
LLSD state_info;
state_info["enum"] = connection_state;
sStateWatcher->post(state_info);
}
}
void FSDiscordConnect::setConnected(bool connected)
{
mConnected = connected;
}

View File

@ -0,0 +1,98 @@
/**
* @file fsdiscordconnect.h
* @brief Connection to Discord
* @author liny@pinkfox.xyz
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
* Phoenix Firestorm Viewer Source Code
* Copyright (C) 2019 Liny Odell @ Second Life
*
* 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
*/
#ifndef FS_FSDISCORDCONNECT_H
#define FS_FSDISCORDCONNECT_H
#include "llsingleton.h"
#include "llcoros.h"
#include "lleventcoro.h"
class LLEventPump;
/**
* @class LLTwitterConnect
*
* Manages authentication to, and interaction with, a web service allowing the
* the viewer to post status updates and upload photos to Twitter.
*/
class FSDiscordConnect : public LLSingleton<FSDiscordConnect>
{
LLSINGLETON(FSDiscordConnect);
LOG_CLASS(FSDiscordConnect);
public:
enum EConnectionState
{
DISCORD_NOT_CONNECTED = 0,
DISCORD_CONNECTION_IN_PROGRESS = 1,
DISCORD_CONNECTED = 2,
DISCORD_CONNECTION_FAILED = 3,
DISCORD_DISCONNECTING = 4
};
~FSDiscordConnect();
void connectToDiscord(); // Initiate the complete Discord connection. Please use checkConnectionToDiscord() in normal use.
void disconnectFromDiscord(); // Disconnect from the Discord service.
void checkConnectionToDiscord(bool auto_connect = false); // Check if connected to the Discord service. If not, call connectToDiscord().
void storeInfo(const LLSD& info);
const LLSD& getInfo() const;
void clearInfo();
void setConnectionState(EConnectionState connection_state);
void setConnected(bool connected);
bool isConnected() { return mConnected; }
EConnectionState getConnectionState() { return mConnectionState; }
void updateRichPresence();
bool Tick(const LLSD&);
private:
EConnectionState mConnectionState;
BOOL mConnected;
LLSD mInfo;
bool mRefreshInfo;
static boost::scoped_ptr<LLEventPump> sStateWatcher;
static boost::scoped_ptr<LLEventPump> sInfoWatcher;
static boost::scoped_ptr<LLEventPump> sContentWatcher;
void discordConnectCoro();
void discordDisconnectCoro();
void discordConnectedCoro(bool autoConnect);
bool checkMarkerFile();
void setMarkerFile();
void clearMarkerFile();
std::string mMarkerFilename;
};
#endif // FS_FSDISCORDCONNECT_H

View File

@ -0,0 +1,323 @@
/**
* @file fsfloaterdiscord.cpp
* @brief Implementation of fsfloaterdiscord.cpp
* @author liny@pinkfox.xyz
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
* Phoenix Firestorm Viewer Source Code
* Copyright (C) 2019 Liny Odell @ Second Life
*
* 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
*/
#include "llviewerprecompiledheaders.h"
#include "fsfloaterdiscord.h"
#include "llagent.h"
#include "llagentui.h"
#include "llcheckboxctrl.h"
#include "llcombobox.h"
#include "fsdiscordconnect.h"
#include "llfloaterreg.h"
#include "lltrans.h"
#include "llviewerregion.h"
#include "llviewercontrol.h"
#include "lltabcontainer.h"
#include "boost/algorithm/string/case_conv.hpp"
////////////////////////
//FSFloaterDiscord///////
////////////////////////
void FSFloaterDiscord::onVisibilityChange(BOOL visible)
{
if(visible)
{
LLEventPumps::instance().obtain("DiscordConnectState").stopListening("FSDiscordAccountPanel");
LLEventPumps::instance().obtain("DiscordConnectState").listen("FSDiscordAccountPanel", boost::bind(&FSFloaterDiscord::onDiscordConnectStateChange, this, _1));
LLEventPumps::instance().obtain("DiscordConnectInfo").stopListening("FSDiscordAccountPanel");
LLEventPumps::instance().obtain("DiscordConnectInfo").listen("FSDiscordAccountPanel", boost::bind(&FSFloaterDiscord::onDiscordConnectInfoChange, this));
LLSD info = FSDiscordConnect::instance().getInfo();
if (info.has("name"))
{
mAccountNameLabel->setText(info["name"].asString());
}
//Connected
if(FSDiscordConnect::instance().isConnected())
{
showConnectedLayout();
}
//Check if connected (show disconnected layout in meantime)
else
{
showDisconnectedLayout();
}
if ((FSDiscordConnect::instance().getConnectionState() == FSDiscordConnect::DISCORD_NOT_CONNECTED) ||
(FSDiscordConnect::instance().getConnectionState() == FSDiscordConnect::DISCORD_CONNECTION_FAILED))
{
FSDiscordConnect::instance().checkConnectionToDiscord();
}
}
else
{
LLEventPumps::instance().obtain("DiscordConnectState").stopListening("FSDiscordAccountPanel");
LLEventPumps::instance().obtain("DiscordConnectInfo").stopListening("FSDiscordAccountPanel");
}
}
void FSFloaterDiscord::onAllow()
{
gSavedPerAccountSettings.setBOOL("FSEnableDiscordIntegration", mAllowCheckbox->get());
}
bool FSFloaterDiscord::onDiscordConnectStateChange(const LLSD& data)
{
if(FSDiscordConnect::instance().isConnected())
{
mAccountCaptionLabel->setText(getString("discord_connected"));
showConnectedLayout();
}
else
{
mAccountCaptionLabel->setText(getString("discord_disconnected"));
showDisconnectedLayout();
}
return false;
}
bool FSFloaterDiscord::onDiscordConnectInfoChange()
{
LLSD info = FSDiscordConnect::instance().getInfo();
if(info.has("name"))
{
mAccountNameLabel->setText(info["name"].asString());
}
return false;
}
void FSFloaterDiscord::showConnectButton()
{
if(!mConnectButton->getVisible())
{
mConnectButton->setVisible(TRUE);
mDisconnectButton->setVisible(FALSE);
}
}
void FSFloaterDiscord::hideConnectButton()
{
if(mConnectButton->getVisible())
{
mConnectButton->setVisible(FALSE);
mDisconnectButton->setVisible(TRUE);
}
}
void FSFloaterDiscord::showDisconnectedLayout()
{
mAccountCaptionLabel->setText(getString("discord_disconnected"));
mAccountNameLabel->setText(std::string(""));
showConnectButton();
}
void FSFloaterDiscord::showConnectedLayout()
{
mAccountCaptionLabel->setText(getString("discord_connected"));
hideConnectButton();
}
void FSFloaterDiscord::onConnect()
{
FSDiscordConnect::instance().checkConnectionToDiscord(true);
}
void FSFloaterDiscord::onDisconnect()
{
FSDiscordConnect::instance().disconnectFromDiscord();
}
FSFloaterDiscord::FSFloaterDiscord(const LLSD& key) : LLFloater(key),
mStatusText(NULL)
{
mCommitCallbackRegistrar.add("FSDiscord.Connect", boost::bind(&FSFloaterDiscord::onConnect, this));
mCommitCallbackRegistrar.add("FSDiscord.Disconnect", boost::bind(&FSFloaterDiscord::onDisconnect, this));
mCommitCallbackRegistrar.add("FSDiscord.Allow", boost::bind(&FSFloaterDiscord::onAllow, this));
mCommitCallbackRegistrar.add("FSDiscord.Combo", boost::bind(&FSFloaterDiscord::onCombo, this));
mCommitCallbackRegistrar.add("FSDiscord.Add", boost::bind(&FSFloaterDiscord::onAdd, this));
mCommitCallbackRegistrar.add("FSDiscord.Rem", boost::bind(&FSFloaterDiscord::onRemove, this));
setVisibleCallback(boost::bind(&FSFloaterDiscord::onVisibilityChange, this, _2));
}
void FSFloaterDiscord::onCombo()
{
gSavedPerAccountSettings.setU32("FSMaxSharedMaturity", mMaturityCombo->getSelectedValue().asInteger());
}
void FSFloaterDiscord::onAdd()
{
std::string name = mBlacklistEntry->getText();
LLStringUtil::trim(name);
if (name == "")
{
return;
}
std::string name_lower = boost::algorithm::to_lower_copy(name);
std::vector<LLScrollListItem*> items = mBlacklistedNames->getAllData();
std::vector<LLScrollListItem*>::iterator itor;
for (itor = items.begin(); itor != items.end(); ++itor)
{
std::string tmp = (*itor)->getValue().asString();
boost::algorithm::to_lower(tmp);
if (tmp == name_lower)
{
return;
}
}
mBlacklistedNames->addSimpleElement(name);
LLSD save;
for (itor = items.begin(); itor != items.end(); ++itor)
{
save.append((*itor)->getValue());
}
save.append(name);
gSavedPerAccountSettings.setLLSD("FSBlacklistedRegionNames", save);
}
void FSFloaterDiscord::onRemove()
{
std::vector<LLScrollListItem*> items = mBlacklistedNames->getAllData();
std::vector<LLScrollListItem*>::iterator itor;
LLSD save = LLSD::emptyArray();
for (itor = items.begin(); itor != items.end(); ++itor)
{
if ((*itor)->getSelected())
{
continue;
}
save.append((*itor)->getValue());
}
mBlacklistedNames->deleteAllItems();
for (LLSD::array_const_iterator iter = save.beginArray();
iter != save.endArray();
iter++)
{
mBlacklistedNames->addSimpleElement(iter->asString());
}
gSavedPerAccountSettings.setLLSD("FSBlacklistedRegionNames", save);
}
void FSFloaterDiscord::onClose(bool app_quitting)
{
if (app_quitting)
{
std::vector<LLScrollListItem*> items = mBlacklistedNames->getAllData();
std::vector<LLScrollListItem*>::iterator itor;
LLSD save = LLSD::emptyArray();
for (itor = items.begin(); itor != items.end(); ++itor)
{
if ((*itor)->getSelected())
{
continue;
}
save.append((*itor)->getValue());
}
gSavedPerAccountSettings.setLLSD("FSBlacklistedRegionNames", save);
}
LLFloater::onClose(app_quitting);
}
BOOL FSFloaterDiscord::postBuild()
{
mAccountCaptionLabel = getChild<LLTextBox>("account_caption_label");
mAccountNameLabel = getChild<LLTextBox>("account_name_label");
mDisconnectButton = getChild<LLButton>("disconnect_btn");
mConnectButton = getChild<LLButton>("connect_btn");
mAllowCheckbox = getChild<LLCheckBoxCtrl>("startup_check");
mMaturityCombo = getChild<LLComboBox>("maturity_desired_combobox");
mBlacklistedNames = getChild<LLScrollListCtrl>("blacklisted_names");
mBlacklistEntry = getChild<LLLineEditor>("blacklist_entry");
mAddBlacklist = getChild<LLButton>("blacklist_entry_add");
mRemBlacklist = getChild<LLButton>("blacklist_entry_rem");
LLSD list = gSavedPerAccountSettings.getLLSD("FSBlacklistedRegionNames");
for (LLSD::array_const_iterator iter = list.beginArray();
iter != list.endArray();
iter++)
{
mBlacklistedNames->addSimpleElement(iter->asString());
}
mMaturityCombo->selectByValue((LLSD::Integer)gSavedPerAccountSettings.getU32("FSMaxSharedMaturity"));
mAllowCheckbox->set(gSavedPerAccountSettings.getBOOL("FSEnableDiscordIntegration"));
// Connection status widgets
mStatusText = getChild<LLTextBox>("connection_status_text");
return LLFloater::postBuild();
}
void FSFloaterDiscord::draw()
{
if (mStatusText)
{
mStatusText->setVisible(false);
FSDiscordConnect::EConnectionState connection_state = FSDiscordConnect::instance().getConnectionState();
std::string status_text;
switch (connection_state)
{
case FSDiscordConnect::DISCORD_NOT_CONNECTED:
// No status displayed when first opening the panel and no connection done
break;
case FSDiscordConnect::DISCORD_CONNECTION_IN_PROGRESS:
// Connection loading indicator
mStatusText->setVisible(true);
status_text = LLTrans::getString("SocialDiscordConnecting");
mStatusText->setValue(status_text);
break;
case FSDiscordConnect::DISCORD_CONNECTED:
// When successfully connected, no message is displayed
break;
case FSDiscordConnect::DISCORD_CONNECTION_FAILED:
// Error connecting to the service
mStatusText->setVisible(true);
status_text = LLTrans::getString("SocialDiscordErrorConnecting");
mStatusText->setValue(status_text);
break;
case FSDiscordConnect::DISCORD_DISCONNECTING:
// Disconnecting loading indicator
mStatusText->setVisible(true);
status_text = LLTrans::getString("SocialDiscordDisconnecting");
mStatusText->setValue(status_text);
break;
}
}
LLFloater::draw();
}

View File

@ -0,0 +1,78 @@
/**
* @file llfloatertwitter.h
* @brief Header file for fsfloaterdiscord
* @author liny@pinkfox.xyz
*
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
* Phoenix Firestorm Viewer Source Code
* Copyright (C) 2019 Liny Odell @ Second Life
*
* 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
*/
#ifndef FS_FSFLOATERDISCORD_H
#define FS_FSFLOATERDISCORD_H
#include "llfloater.h"
#include "lltextbox.h"
class LLCheckBoxCtrl;
class LLComboBox;
class LLScrollListCtrl;
class LLLineEditor;
class FSFloaterDiscord : public LLFloater
{
public:
FSFloaterDiscord(const LLSD& key);
BOOL postBuild();
void draw();
void onClose(bool app_quitting);
private:
void onVisibilityChange(BOOL visible);
bool onDiscordConnectStateChange(const LLSD& data);
bool onDiscordConnectInfoChange();
void onConnect();
void onUseAnotherAccount();
void onDisconnect();
void onAllow();
void onCombo();
void onAdd();
void onRemove();
void showConnectButton();
void hideConnectButton();
void showDisconnectedLayout();
void showConnectedLayout();
LLTextBox * mAccountCaptionLabel;
LLTextBox * mAccountNameLabel;
LLButton * mConnectButton;
LLButton * mDisconnectButton;
LLCheckBoxCtrl * mAllowCheckbox;
LLComboBox * mMaturityCombo;
LLScrollListCtrl * mBlacklistedNames;
LLLineEditor * mBlacklistEntry;
LLButton * mAddBlacklist;
LLButton * mRemBlacklist;
LLTextBox* mStatusText;
};
#endif // FS_FSFLOATERDISCORD_H

View File

@ -180,6 +180,7 @@
#include "fsfloateravatarrendersettings.h"
#include "fsfloatercontacts.h"
#include "fsfloatercontactsetconfiguration.h"
#include "fsfloaterdiscord.h"
#include "fsfloaterexport.h"
#include "fsfloaterblocklist.h"
#include "fsfloatergroup.h"
@ -465,6 +466,7 @@ void LLViewerFloaterReg::registerFloaters()
LLFloaterReg::add("fs_blocklist", "floater_fs_blocklist.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<FSFloaterBlocklist>);
LLFloaterReg::add("fs_add_contact", "floater_fs_contact_add.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<FSFloaterAddToContactSet>);
LLFloaterReg::add("fs_contact_set_config", "floater_fs_contact_set_configuration.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<FSFloaterContactSetConfiguration>);
LLFloaterReg::add("fs_discord", "floater_fs_discord.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<FSFloaterDiscord>);
LLFloaterReg::add("fs_group", "floater_fs_group.xml",&LLFloaterReg::build<FSFloaterGroup>);
LLFloaterReg::add("fs_group_titles", "floater_fs_group_titles.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<FSFloaterGroupTitles>);
LLFloaterReg::add("fs_export", "floater_fs_export.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<FSFloaterObjectExport>);

View File

@ -130,6 +130,8 @@
#include "llsidepanelappearance.h"
#include "fsavatarrenderpersistence.h"
#include "fsdiscordconnect.h" // <FS:LO> tapping a place that happens on landing in world to start up discord
extern F32 SPEED_ADJUST_MAX;
extern F32 SPEED_ADJUST_MAX_SEC;
extern F32 ANIM_SPEED_MAX;
@ -3078,6 +3080,8 @@ void LLVOAvatar::idleUpdateLoadingEffect()
// <FS:Zi> Animation Overrider
AOEngine::instance().onLoginComplete();
// <FS:LO> tapping a place that happens on landing in world to start up discord
FSDiscordConnect::instance().checkConnectionToDiscord(gSavedPerAccountSettings.getBOOL("FSEnableDiscordIntegration"));
}
else
{

View File

@ -1031,6 +1031,8 @@ with the same filename but different name
<texture name="Icon_DialogStack" file_name="icons/Icon_DialogStack.png" preload="false" />
<texture name="Command_Discord_Icon" file_name="toolbar_icons/discord.png" preload="true" />
<!-- Higher Resolution 200px Loading Progress Indicator -->
<texture name="ProgressLarge_1" file_name="icons/ProgressLarge_1.png" preload="true" />
<texture name="ProgressLarge_2" file_name="icons/ProgressLarge_2.png" preload="true" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 B

View File

@ -0,0 +1,189 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<floater
positioning="cascading"
can_close="true"
can_resize="false"
help_topic="floater_discord"
layout="topleft"
name="floater_discord"
save_rect="true"
single_instance="true"
reuse_instance="true"
title="Discord"
height="462"
width="272">
<string
name="discord_connected"
value="You are connected to Discord as:" />
<string
name="discord_disconnected"
value="Not connected to Discord" />
<string name="SocialDiscordConnecting">Connecting to Discord</string>
<string name="SocialDiscordErrorConnecting">Error connecting to Discord</string>
<string name="SocialDiscordDisconnecting">Disconnecting from Discord</string>
<text
layout="topleft"
length="1"
follows="top|left"
font="SansSerif"
height="16"
left="10"
name="account_caption_label"
top="5"
type="string">
Not connected to Discord.
</text>
<text
layout="topleft"
top_pad="2"
length="1"
follows="top|left"
font="SansSerif"
height="16"
left="10"
name="account_name_label"
parse_urls="true"
type="string"/>
<check_box
layout="topleft"
follows="left|top|right"
top_pad="9"
left="10"
right="-10"
visible="true"
height="23"
label="Automaticly connect to Discord on login?"
name="startup_check"
width="210">
<commit_callback function="FSDiscord.Allow"/>
</check_box>
<button
layout="topleft"
follows="left|top|right"
top_pad="9"
left="10"
right="-10"
visible="true"
height="23"
label="Connect..."
name="connect_btn"
width="210">
<commit_callback function="FSDiscord.Connect"/>
</button>
<button
layout="topleft"
follows="left|top|right"
top_delta="0"
left="10"
right="-10"
height="23"
label="Disconnect"
name="disconnect_btn"
width="210"
visible="false">
<commit_callback function="FSDiscord.Disconnect"/>
</button>
<text
layout="topleft"
length="1"
follows="top|left"
font="SansSerif"
height="26"
word_wrap="true"
left="10"
name="dont_show_higher_label"
top_pad="5"
type="string">
Dont share region names to Discord if the maturity is higher than:
</text>
<combo_box
follows="left|top"
height="23"
layout="topleft"
name="maturity_desired_combobox"
width="200">
<combo_box.item
label="General, Moderate, Adult"
name="Desired_Adult"
value="42" />
<combo_box.item
label="General and Moderate"
name="Desired_Mature"
value="21" />
<combo_box.item
label="General"
name="Desired_PG"
value="13" />
<commit_callback function="FSDiscord.Combo"/>
</combo_box>
<text
layout="topleft"
length="1"
follows="top|left"
font="SansSerif"
height="26"
word_wrap="true"
left="10"
name="dont_names_label"
top_pad="5"
type="string">
Dont share region names to Discord if they are listed below:
</text>
<scroll_list
follows="top|left|right"
height="215"
layout="topleft"
left="10"
multi_select="true"
name="blacklisted_names"
sort_column="0"
sort_ascending="true"
width="250" />
<line_editor
follows="left|top"
bottom_delta="24"
height="20"
max_length_chars="256"
name="blacklist_entry"
width="202">
<commit_callback function="FSDiscord.Add"/>
</line_editor>
<button
follows="left|top"
height="20"
image_overlay="AddItem_Off"
layout="topleft"
left_pad="4"
name="blacklist_entry_add"
scale_image="true"
width="20">
<commit_callback function="FSDiscord.Add"/>
</button>
<button
follows="left|top"
height="20"
image_overlay="MinusItem_Off"
layout="topleft"
left_pad="4"
name="blacklist_entry_rem"
scale_image="true"
width="20">
<commit_callback function="FSDiscord.Rem"/>
</button>
<text
name="connection_status_text"
type="string"
follows="left|bottom|right"
bottom_delta="20"
left="-262"
width="223"
height="20"
wrap="true"
halign="left"
valign="center"
text_color="EmphasisColor"
font="SansSerif">
Loading...
</text>
</floater>

View File

@ -604,6 +604,13 @@
<menu_item_call.on_click
function="Floater.Toggle"
parameter="flickr"/>
</menu_item_call>
<menu_item_call
label="Discord..."
name="Discord">
<menu_item_call.on_click
function="Floater.Toggle"
parameter="fs_discord"/>
</menu_item_call>
<menu_item_separator/>
<menu

View File

@ -234,6 +234,11 @@ Please try logging in again in a minute.</string>
<string name="SocialTwitterErrorConnecting">Problem connecting to Twitter</string>
<string name="SocialTwitterErrorPosting">Problem posting to Twitter</string>
<string name="SocialTwitterErrorDisconnecting">Problem disconnecting from Twitter</string>
<!-- Firestorm social strings -->
<string name="SocialDiscordConnecting">Connecting to Discord</string>
<string name="SocialDiscordErrorConnecting">Error connecting to Discord</string>
<string name="SocialDiscordDisconnecting">Disconnecting from Discord</string>
<!-- SLShare: User Friendly Filter Names Translation -->
<string name="BlackAndWhite">Black &amp; White</string>
@ -2712,6 +2717,9 @@ Try enclosing path to the editor with double quotes.
<string name="Command_Fly_Tooltip">Toggle flying mode on/off (HOME)</string>
<string name="Command_Stop_Animations_Label">Stop Animations</string>
<string name="Command_Stop_Animations_Tooltip">Stop Animating my Avatar</string>
<string name="Command_Discord_Label">Discord</string>
<string name="Command_Discord_Tooltip">Discord</string>
<!-- Mesh UI terms -->
<string name="Retain%">Retain%</string>