summaryrefslogtreecommitdiff
path: root/indra/newview/llviewerparcelaskplay.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llviewerparcelaskplay.cpp')
-rw-r--r--indra/newview/llviewerparcelaskplay.cpp306
1 files changed, 306 insertions, 0 deletions
diff --git a/indra/newview/llviewerparcelaskplay.cpp b/indra/newview/llviewerparcelaskplay.cpp
new file mode 100644
index 0000000000..afbe2c94de
--- /dev/null
+++ b/indra/newview/llviewerparcelaskplay.cpp
@@ -0,0 +1,306 @@
+/**
+ * @file llviewerparcelaskplay.cpp
+ * @brief stores data about parcel media user wants to auto-play and shows related notifications
+ *
+ * $LicenseInfo:firstyear=2019&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2019, Linden Research, 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
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llviewerparcelaskplay.h"
+
+#include "llnotifications.h"
+#include "llnotificationsutil.h"
+#include "llparcel.h"
+#include "llstartup.h"
+#include "llviewerparcelmgr.h"
+#include "llviewerregion.h"
+#include "llagent.h"
+#include "llsdserialize.h"
+
+#include <boost/lexical_cast.hpp>
+
+
+// class LLViewerParcelAskPlay
+
+LLViewerParcelAskPlay::LLViewerParcelAskPlay() :
+pNotification(NULL)
+{
+}
+
+LLViewerParcelAskPlay::~LLViewerParcelAskPlay()
+{
+
+}
+
+void LLViewerParcelAskPlay::initSingleton()
+{
+
+}
+void LLViewerParcelAskPlay::cleanupSingleton()
+{
+ if (LLNotifications::instanceExists())
+ {
+ cancelNotification();
+ }
+}
+
+void LLViewerParcelAskPlay::askToPlay(const LLUUID &region_id, const S32 &parcel_id, const std::string &url, ask_callback cb)
+{
+ EAskPlayMode mode = getPlayMode(region_id, parcel_id);
+
+ switch (mode)
+ {
+ case ASK_PLAY_IGNORE:
+ cb(region_id, parcel_id, url, false);
+ break;
+ case ASK_PLAY_PLAY:
+ cb(region_id, parcel_id, url, true);
+ break;
+ case ASK_PLAY_ASK:
+ default:
+ {
+ // create or re-create notification
+ // Note: will create and immediately cancel one notification if region has both media and music
+ // since ask play does not distinguish media from music and media can be used as music
+ cancelNotification();
+
+ if (LLStartUp::getStartupState() > STATE_PRECACHE)
+ {
+ LLSD args;
+ args["URL"] = url;
+ LLSD payload;
+ payload["url"] = url; // or we can extract it from notification["substitutions"]
+ payload["parcel_id"] = parcel_id;
+ payload["region_id"] = region_id;
+ pNotification = LLNotificationsUtil::add("ParcelPlayingMedia", args, payload, boost::bind(onAskPlayResponse, _1, _2, cb));
+ }
+ else
+ {
+ // workaround: avoid 'new notifications arrived' on startup and just play
+ // (alternative: move to different channel, may be create new one...)
+ cb(region_id, parcel_id, url, true);
+ }
+ }
+ }
+}
+
+void LLViewerParcelAskPlay::cancelNotification()
+{
+ if (pNotification)
+ {
+ if (!pNotification->isCancelled())
+ {
+ // Force a responce
+ // Alternative is to mark notification as unique
+ pNotification->setIgnored(false);
+ LLNotifications::getInstance()->cancel(pNotification);
+ }
+ pNotification = NULL;
+ }
+}
+
+void LLViewerParcelAskPlay::resetCurrentParcelSetting()
+{
+ LLParcel *agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+ if (agent_parcel && gAgent.getRegion())
+ {
+ LLViewerParcelAskPlay::resetSetting(gAgent.getRegion()->getRegionID(), agent_parcel->getLocalID());
+ }
+}
+
+void LLViewerParcelAskPlay::resetSetting(const LLUUID &region_id, const S32 &parcel_id)
+{
+ region_map_t::iterator found = mRegionMap.find(region_id);
+ if (found != mRegionMap.end())
+ {
+ found->second.erase(parcel_id);
+ }
+}
+
+void LLViewerParcelAskPlay::resetSettings()
+{
+ if (LLViewerParcelAskPlay::instanceExists())
+ {
+ LLViewerParcelAskPlay::getInstance()->mRegionMap.clear();
+ }
+ LLFile::remove(getAskPlayFilename());
+}
+
+void LLViewerParcelAskPlay::setSetting(const LLUUID &region_id, const S32 &parcel_id, const LLViewerParcelAskPlay::ParcelData &data)
+{
+ mRegionMap[region_id][parcel_id] = data;
+}
+
+LLViewerParcelAskPlay::ParcelData* LLViewerParcelAskPlay::getSetting(const LLUUID &region_id, const S32 &parcel_id)
+{
+ region_map_t::iterator found = mRegionMap.find(region_id);
+ if (found != mRegionMap.end())
+ {
+ parcel_data_map_t::iterator found_parcel = found->second.find(parcel_id);
+ if (found_parcel != found->second.end())
+ {
+ return &(found_parcel->second);
+ }
+ }
+ return NULL;
+}
+
+LLViewerParcelAskPlay::EAskPlayMode LLViewerParcelAskPlay::getPlayMode(const LLUUID &region_id, const S32 &parcel_id)
+{
+ EAskPlayMode mode = ASK_PLAY_ASK;
+ ParcelData* data = getSetting(region_id, parcel_id);
+ if (data)
+ {
+ mode = data->mMode;
+ // refresh date
+ data->mDate = LLDate::now();
+ }
+ return mode;
+}
+
+void LLViewerParcelAskPlay::setPlayMode(const LLUUID &region_id, const S32 &parcel_id, LLViewerParcelAskPlay::EAskPlayMode mode)
+{
+ ParcelData data;
+ data.mMode = mode;
+ data.mDate = LLDate::now();
+ setSetting(region_id, parcel_id, data);
+}
+
+//static
+void LLViewerParcelAskPlay::onAskPlayResponse(const LLSD& notification, const LLSD& response, ask_callback cb)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+
+ LLUUID region_id = notification["payload"]["region_id"];
+ S32 parcel_id = notification["payload"]["parcel_id"];
+ std::string url = notification["payload"]["url"];
+
+ bool play = option == 1;
+
+ cb(region_id, parcel_id, url, play);
+
+ LLViewerParcelAskPlay *inst = getInstance();
+ bool save_choice = inst->pNotification->isIgnored(); // checkbox selected
+ if (save_choice)
+ {
+ EAskPlayMode mode = (play) ? ASK_PLAY_PLAY : ASK_PLAY_IGNORE;
+ inst->setPlayMode(region_id, parcel_id, mode);
+ }
+}
+
+// static
+std::string LLViewerParcelAskPlay::getAskPlayFilename()
+{
+ return gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "media_autoplay.xml");
+}
+
+void LLViewerParcelAskPlay::loadSettings()
+{
+ mRegionMap.clear();
+
+ std::string path = getAskPlayFilename();
+ if (!gDirUtilp->fileExists(path))
+ {
+ return;
+ }
+
+ LLSD autoplay_llsd;
+ llifstream file;
+ file.open(path.c_str());
+ if (!file.is_open())
+ {
+ return;
+ }
+ S32 status = LLSDSerialize::fromXML(autoplay_llsd, file);
+ file.close();
+
+ if (status == LLSDParser::PARSE_FAILURE || !autoplay_llsd.isMap())
+ {
+ return;
+ }
+
+ for (LLSD::map_const_iterator iter_region = autoplay_llsd.beginMap();
+ iter_region != autoplay_llsd.endMap(); ++iter_region)
+ {
+ LLUUID region_id = LLUUID(iter_region->first);
+ mRegionMap[region_id] = parcel_data_map_t();
+
+ const LLSD &parcel_map = iter_region->second;
+
+ if (parcel_map.isMap())
+ {
+ for (LLSD::map_const_iterator iter_parcel = parcel_map.beginMap();
+ iter_parcel != parcel_map.endMap(); ++iter_parcel)
+ {
+ if (!iter_parcel->second.isMap())
+ {
+ break;
+ }
+ S32 parcel_id = boost::lexical_cast<S32>(iter_parcel->first.c_str());
+ ParcelData data;
+ data.mMode = (EAskPlayMode)(iter_parcel->second["mode"].asInteger());
+ data.mDate = iter_parcel->second["date"].asDate();
+ mRegionMap[region_id][parcel_id] = data;
+ }
+ }
+ }
+}
+
+void LLViewerParcelAskPlay::saveSettings()
+{
+ LLSD write_llsd;
+ std::string key;
+ for (region_map_t::iterator iter_region = mRegionMap.begin();
+ iter_region != mRegionMap.end(); ++iter_region)
+ {
+ if (iter_region->second.empty())
+ {
+ continue;
+ }
+ key = iter_region->first.asString();
+ write_llsd[key] = LLSD();
+
+ for (parcel_data_map_t::iterator iter_parcel = iter_region->second.begin();
+ iter_parcel != iter_region->second.end(); ++iter_parcel)
+ {
+ if ((iter_parcel->second.mDate.secondsSinceEpoch() + (F64SecondsImplicit)U32Days(30)) > LLTimer::getTotalSeconds())
+ {
+ // write unexpired parcels
+ std::string parcel_id = boost::lexical_cast<std::string>(iter_parcel->first);
+ write_llsd[key][parcel_id] = LLSD();
+ write_llsd[key][parcel_id]["mode"] = (LLSD::Integer)iter_parcel->second.mMode;
+ write_llsd[key][parcel_id]["date"] = iter_parcel->second.mDate;
+ }
+ }
+ }
+
+ llofstream file;
+ file.open(getAskPlayFilename().c_str());
+ if (file.is_open())
+ {
+ LLSDSerialize::toPrettyXML(write_llsd, file);
+ file.close();
+ }
+}
+