summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorandreykproductengine <andreykproductengine@lindenlab.com>2019-09-05 17:15:57 +0300
committerandreykproductengine <andreykproductengine@lindenlab.com>2019-09-05 17:15:57 +0300
commite29b3605c31e2e1cbbc932ce75b327f98b70f513 (patch)
tree6f6c3bd3aeb51935e270b2e281583fe4a48d7078 /indra
parent611e0a2e38d624ed22270f2148323c320df5cc39 (diff)
SL-11315 Viewer asks to play media and retains selected choice
Diffstat (limited to 'indra')
-rw-r--r--indra/llui/llnotifications.cpp17
-rw-r--r--indra/llui/llnotifications.h4
-rw-r--r--indra/newview/CMakeLists.txt2
-rw-r--r--indra/newview/app_settings/settings.xml4
-rw-r--r--indra/newview/llappviewer.cpp6
-rw-r--r--indra/newview/llfloaterpreference.cpp8
-rw-r--r--indra/newview/llfloaterpreference.h1
-rw-r--r--indra/newview/llpanelnearbymedia.cpp23
-rw-r--r--indra/newview/llpanelvolumepulldown.cpp2
-rw-r--r--indra/newview/llstartup.cpp5
-rw-r--r--indra/newview/lltoastalertpanel.cpp1
-rw-r--r--indra/newview/lltoastnotifypanel.cpp7
-rw-r--r--indra/newview/lltoastpanel.cpp15
-rw-r--r--indra/newview/llviewermedia.cpp14
-rw-r--r--indra/newview/llviewermedia.h1
-rw-r--r--indra/newview/llviewerparcelaskplay.cpp301
-rw-r--r--indra/newview/llviewerparcelaskplay.h89
-rw-r--r--indra/newview/llviewerparcelmediaautoplay.cpp53
-rw-r--r--indra/newview/llviewerparcelmediaautoplay.h3
-rw-r--r--indra/newview/llviewerparcelmgr.cpp57
-rw-r--r--indra/newview/llviewerparcelmgr.h3
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml28
-rw-r--r--indra/newview/skins/default/xui/en/panel_preferences_sound.xml45
23 files changed, 630 insertions, 59 deletions
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 7bafd711cb..2e6dc6731b 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -68,7 +68,8 @@ LLNotificationForm::FormIgnore::FormIgnore()
control("control"),
invert_control("invert_control", false),
save_option("save_option", false),
- session_only("session_only", false)
+ session_only("session_only", false),
+ checkbox_only("checkbox_only", false)
{}
LLNotificationForm::FormButton::FormButton()
@@ -195,9 +196,14 @@ LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotifica
{
if (p.ignore.isProvided())
{
+ // For all cases but IGNORE_CHECKBOX_ONLY this is name for use in preferences
mIgnoreMsg = p.ignore.text;
- if (!p.ignore.save_option)
+ if (p.ignore.checkbox_only)
+ {
+ mIgnore = IGNORE_CHECKBOX_ONLY;
+ }
+ else if (!p.ignore.save_option)
{
mIgnore = p.ignore.session_only ? IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY : IGNORE_WITH_DEFAULT_RESPONSE;
}
@@ -214,7 +220,7 @@ LLNotificationForm::LLNotificationForm(const std::string& name, const LLNotifica
mIgnoreSetting = LLUI::sSettingGroups["config"]->getControl(p.ignore.control);
mInvertSetting = p.ignore.invert_control;
}
- else
+ else if (mIgnore > IGNORE_NO)
{
LLUI::sSettingGroups["ignores"]->declareBOOL(name, show_notification, "Show notification with this name", LLControlVariable::PERSIST_NONDFT);
mIgnoreSetting = LLUI::sSettingGroups["ignores"]->getControl(name);
@@ -388,13 +394,12 @@ LLControlVariablePtr LLNotificationForm::getIgnoreSetting()
bool LLNotificationForm::getIgnored()
{
bool show = true;
- if (mIgnore != LLNotificationForm::IGNORE_NO
+ if (mIgnore > LLNotificationForm::IGNORE_NO
&& mIgnoreSetting)
{
show = mIgnoreSetting->getValue().asBoolean();
if (mInvertSetting) show = !show;
}
-
return !show;
}
@@ -695,7 +700,7 @@ void LLNotification::respond(const LLSD& response)
mTemporaryResponder = false;
}
- if (mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO)
+ if (mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO)
{
mForm->setIgnored(mIgnored);
if (mIgnored && mForm->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE)
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 1509446920..62cf41256b 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -180,6 +180,7 @@ public:
Optional<std::string> control;
Optional<bool> invert_control;
Optional<bool> session_only;
+ Optional<bool> checkbox_only;
FormIgnore();
};
@@ -232,7 +233,8 @@ public:
typedef enum e_ignore_type
{
- IGNORE_NO,
+ IGNORE_CHECKBOX_ONLY = -1, // ignore won't be handled, will set value/checkbox only
+ IGNORE_NO = 0,
IGNORE_WITH_DEFAULT_RESPONSE,
IGNORE_WITH_DEFAULT_RESPONSE_SESSION_ONLY,
IGNORE_WITH_LAST_RESPONSE,
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 0ca5a08dfc..95a916d7cb 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -664,6 +664,7 @@ set(viewer_SOURCE_FILES
llviewerobject.cpp
llviewerobjectlist.cpp
llvieweroctree.cpp
+ llviewerparcelaskplay.cpp
llviewerparcelmedia.cpp
llviewerparcelmediaautoplay.cpp
llviewerparcelmgr.cpp
@@ -1284,6 +1285,7 @@ set(viewer_HEADER_FILES
llviewerobject.h
llviewerobjectlist.h
llvieweroctree.h
+ llviewerparcelaskplay.h
llviewerparcelmedia.h
llviewerparcelmediaautoplay.h
llviewerparcelmgr.h
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index f54f683757..b9cb613b96 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -7494,11 +7494,11 @@
<key>ParcelMediaAutoPlayEnable</key>
<map>
<key>Comment</key>
- <string>Auto play parcel media when available</string>
+ <string>Auto play parcel media when available. 0 - Do not autoplay; 1- Autoplay; 2 - Ask</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
- <string>Boolean</string>
+ <string>S32</string>
<key>Value</key>
<integer>1</integer>
</map>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 12a459b2b8..2a928a47a2 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -68,6 +68,7 @@
#include "llviewerwindow.h"
#include "llviewerdisplay.h"
#include "llviewermedia.h"
+#include "llviewerparcelaskplay.h"
#include "llviewerparcelmedia.h"
#include "llviewermediafocus.h"
#include "llviewermessage.h"
@@ -1938,6 +1939,11 @@ bool LLAppViewer::cleanup()
{
gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE);
LL_INFOS() << "Saved settings" << LL_ENDL;
+
+ if (LLViewerParcelAskPlay::instanceExists())
+ {
+ LLViewerParcelAskPlay::getInstance()->saveSettings();
+ }
}
std::string warnings_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Warnings"));
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 9d0e1972a3..b48495b5b2 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -1242,7 +1242,7 @@ void LLFloaterPreference::buildPopupLists()
LLNotificationFormPtr formp = templatep->mForm;
LLNotificationForm::EIgnoreType ignore = formp->getIgnoreType();
- if (ignore == LLNotificationForm::IGNORE_NO)
+ if (ignore <= LLNotificationForm::IGNORE_NO)
continue;
LLSD row;
@@ -1824,7 +1824,7 @@ void LLFloaterPreference::resetAllIgnored()
iter != LLNotifications::instance().templatesEnd();
++iter)
{
- if (iter->second->mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO)
+ if (iter->second->mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO)
{
iter->second->mForm->setIgnored(false);
}
@@ -1837,7 +1837,7 @@ void LLFloaterPreference::setAllIgnored()
iter != LLNotifications::instance().templatesEnd();
++iter)
{
- if (iter->second->mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO)
+ if (iter->second->mForm->getIgnoreType() > LLNotificationForm::IGNORE_NO)
{
iter->second->mForm->setIgnored(true);
}
@@ -2674,7 +2674,7 @@ void LLPanelPreference::updateMediaAutoPlayCheckbox(LLUICtrl* ctrl)
bool music_enabled = getChild<LLCheckBoxCtrl>("enable_music")->get();
bool media_enabled = getChild<LLCheckBoxCtrl>("enable_media")->get();
- getChild<LLCheckBoxCtrl>("media_auto_play_btn")->setEnabled(music_enabled || media_enabled);
+ getChild<LLCheckBoxCtrl>("media_auto_play_combo")->setEnabled(music_enabled || media_enabled);
}
}
diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h
index 8345ad1bb6..4412c95473 100644
--- a/indra/newview/llfloaterpreference.h
+++ b/indra/newview/llfloaterpreference.h
@@ -168,7 +168,6 @@ public:
void refreshUI();
- void onCommitParcelMediaAutoPlayEnable();
void onCommitMediaEnabled();
void onCommitMusicEnabled();
void applyResolution();
diff --git a/indra/newview/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp
index f3a2ed9408..af28ff8e61 100644
--- a/indra/newview/llpanelnearbymedia.cpp
+++ b/indra/newview/llpanelnearbymedia.cpp
@@ -43,6 +43,7 @@
#include "llbutton.h"
#include "lltextbox.h"
#include "llviewermedia.h"
+#include "llviewerparcelaskplay.h"
#include "llviewerparcelmedia.h"
#include "llviewerregion.h"
#include "llviewermediafocus.h"
@@ -83,10 +84,11 @@ LLPanelNearByMedia::LLPanelNearByMedia()
{
mHoverTimer.stop();
- mParcelAudioAutoStart = gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) &&
- gSavedSettings.getBOOL("MediaTentativeAutoPlay");
+ // This is just an initial value, mParcelAudioAutoStart does not affect ParcelMediaAutoPlayEnable
+ mParcelAudioAutoStart = gSavedSettings.getS32("ParcelMediaAutoPlayEnable") != 0
+ && gSavedSettings.getBOOL("MediaTentativeAutoPlay");
- gSavedSettings.getControl(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING)->getSignal()->connect(boost::bind(&LLPanelNearByMedia::handleMediaAutoPlayChanged, this, _2));
+ gSavedSettings.getControl("ParcelMediaAutoPlayEnable")->getSignal()->connect(boost::bind(&LLPanelNearByMedia::handleMediaAutoPlayChanged, this, _2));
mCommitCallbackRegistrar.add("MediaListCtrl.EnableAll", boost::bind(&LLPanelNearByMedia::onClickEnableAll, this));
mCommitCallbackRegistrar.add("MediaListCtrl.DisableAll", boost::bind(&LLPanelNearByMedia::onClickDisableAll, this));
@@ -177,9 +179,18 @@ BOOL LLPanelNearByMedia::postBuild()
void LLPanelNearByMedia::handleMediaAutoPlayChanged(const LLSD& newvalue)
{
- // update mParcelAudioAutoStart if AUTO_PLAY_MEDIA_SETTING changes
- mParcelAudioAutoStart = gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) &&
- gSavedSettings.getBOOL("MediaTentativeAutoPlay");
+ // update mParcelAudioAutoStartMode if "ParcelMediaAutoPlayEnable" changes
+ S32 value = gSavedSettings.getS32("ParcelMediaAutoPlayEnable");
+ mParcelAudioAutoStart = value != 0
+ && gSavedSettings.getBOOL("MediaTentativeAutoPlay");
+
+ LLViewerParcelAskPlay *inst = LLViewerParcelAskPlay::getInstance();
+ if (value == 2 && !inst->hasData())
+ {
+ // Init if nessesary
+ inst->loadSettings();
+ }
+ inst->cancelNotification();
}
/*virtual*/
diff --git a/indra/newview/llpanelvolumepulldown.cpp b/indra/newview/llpanelvolumepulldown.cpp
index 6792137350..f063d84272 100644
--- a/indra/newview/llpanelvolumepulldown.cpp
+++ b/indra/newview/llpanelvolumepulldown.cpp
@@ -140,7 +140,7 @@ void LLPanelVolumePulldown::updateMediaAutoPlayCheckbox(LLUICtrl* ctrl)
bool music_enabled = getChild<LLCheckBoxCtrl>("enable_music")->get();
bool media_enabled = getChild<LLCheckBoxCtrl>("enable_media")->get();
- getChild<LLCheckBoxCtrl>("media_auto_play_btn")->setEnabled(music_enabled || media_enabled);
+ getChild<LLCheckBoxCtrl>("media_auto_play_combo")->setEnabled(music_enabled || media_enabled);
}
}
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 77aa7b36b9..5f235c05a6 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -158,6 +158,7 @@
#include "llviewermessage.h"
#include "llviewernetwork.h"
#include "llviewerobjectlist.h"
+#include "llviewerparcelaskplay.h"
#include "llviewerparcelmedia.h"
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
@@ -1425,6 +1426,10 @@ bool idle_startup()
// create a container's instance for start a controlling conversation windows
// by the voice's events
LLFloaterIMContainer::getInstance();
+ if (gSavedSettings.getS32("ParcelMediaAutoPlayEnable") == 2)
+ {
+ LLViewerParcelAskPlay::getInstance()->loadSettings();
+ }
// *Note: this is where gWorldMap used to be initialized.
diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp
index 023d1a685c..8df83c64cd 100644
--- a/indra/newview/lltoastalertpanel.cpp
+++ b/indra/newview/lltoastalertpanel.cpp
@@ -34,7 +34,6 @@
#include "llfontgl.h"
#include "lltextbox.h"
#include "llbutton.h"
-#include "llcheckboxctrl.h"
#include "llkeyboard.h"
#include "llfocusmgr.h"
#include "lliconctrl.h"
diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp
index 83009a78d4..bccf88128d 100644
--- a/indra/newview/lltoastnotifypanel.cpp
+++ b/indra/newview/lltoastnotifypanel.cpp
@@ -163,6 +163,11 @@ void LLToastNotifyPanel::updateButtonsLayout(const std::vector<index_button_pair
{
left = (max_width - btn_rect.getWidth()) / 2;
}
+ else if (left == 0 && buttons.size() == 2)
+ {
+ // Note: this and "size() == 1" shouldn't be inside the cycle, might be good idea to refactor whole placing process
+ left = (max_width - (btn_rect.getWidth() * 2) - h_pad) / 2;
+ }
else if (left + btn_rect.getWidth() > max_width)// whether there is still some place for button+h_pad in the mControlPanel
{
// looks like we need to add button to the next row
@@ -412,7 +417,7 @@ void LLToastNotifyPanel::init( LLRect rect, bool show_images )
mInfoPanel->setFollowsAll();
// Add checkbox (one of couple types) if nessesary.
- setCheckBoxes(HPAD * 3, 0, mInfoPanel);
+ setCheckBoxes(HPAD * 2, 0, mInfoPanel);
if (mCheck)
{
mCheck->setFollows(FOLLOWS_BOTTOM | FOLLOWS_LEFT);
diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp
index 1abd35d931..100d5ee713 100644
--- a/indra/newview/lltoastpanel.cpp
+++ b/indra/newview/lltoastpanel.cpp
@@ -161,7 +161,20 @@ void LLCheckBoxToastPanel::setCheckBoxes(const S32 &h_pad, const S32 &v_pad, LLV
std::string ignore_label;
LLNotificationFormPtr form = mNotification->getForm();
- if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE)
+ if (form->getIgnoreType() == LLNotificationForm::IGNORE_CHECKBOX_ONLY)
+ {
+ // Normally text is only used to describe notification in preferences,
+ // but this one is not displayed in preferences and works on case by case
+ // basis.
+ // Display text if present, display 'always chose' if not.
+ std::string ignore_message = form->getIgnoreMessage();
+ if (ignore_message.empty())
+ {
+ ignore_message = LLNotifications::instance().getGlobalString("alwayschoose");
+ }
+ setCheckBox(ignore_message, ignore_label, boost::bind(&LLCheckBoxToastPanel::onCommitCheckbox, this, _1), h_pad, v_pad, parent_view);
+ }
+ else if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE)
{
setCheckBox(LLNotifications::instance().getGlobalString("skipnexttime"), ignore_label, boost::bind(&LLCheckBoxToastPanel::onCommitCheckbox, this, _1), h_pad, v_pad, parent_view);
}
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index a9eb79b649..c97a42bf06 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -57,6 +57,7 @@
#include "llviewercontrol.h"
#include "llviewermenufile.h" // LLFilePickerThread
#include "llviewernetwork.h"
+#include "llviewerparcelaskplay.h"
#include "llviewerparcelmedia.h"
#include "llviewerparcelmgr.h"
#include "llviewerregion.h"
@@ -77,7 +78,6 @@
#include <boost/bind.hpp> // for SkinFolder listener
#include <boost/signals2.hpp>
-/*static*/ const char* LLViewerMedia::AUTO_PLAY_MEDIA_SETTING = "ParcelMediaAutoPlayEnable";
/*static*/ const char* LLViewerMedia::SHOW_MEDIA_ON_OTHERS_SETTING = "MediaShowOnOthers";
/*static*/ const char* LLViewerMedia::SHOW_MEDIA_WITHIN_PARCEL_SETTING = "MediaShowWithinParcel";
/*static*/ const char* LLViewerMedia::SHOW_MEDIA_OUTSIDE_PARCEL_SETTING = "MediaShowOutsideParcel";
@@ -1005,12 +1005,14 @@ void LLViewerMedia::setAllMediaPaused(bool val)
}
}
+ LLParcel *agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+
// Also do Parcel Media and Parcel Audio
if (!val)
{
if (!LLViewerMedia::isParcelMediaPlaying() && LLViewerMedia::hasParcelMedia())
{
- LLViewerParcelMedia::play(LLViewerParcelMgr::getInstance()->getAgentParcel());
+ LLViewerParcelMedia::play(agent_parcel);
}
static LLCachedControl<bool> audio_streaming_music(gSavedSettings, "AudioStreamingMusic", true);
@@ -1038,6 +1040,12 @@ void LLViewerMedia::setAllMediaPaused(bool val)
LLViewerAudio::getInstance()->stopInternetStreamWithAutoFade();
}
}
+
+ // remove play choice for current parcel
+ if (agent_parcel && gAgent.getRegion())
+ {
+ LLViewerParcelAskPlay::getInstance()->resetSetting(gAgent.getRegion()->getRegionID(), agent_parcel->getLocalID());
+ }
}
//////////////////////////////////////////////////////////////////////////////////////////
@@ -3777,7 +3785,7 @@ void LLViewerMediaImpl::setTextureID(LLUUID id)
bool LLViewerMediaImpl::isAutoPlayable() const
{
return (mMediaAutoPlay &&
- gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) &&
+ gSavedSettings.getS32("ParcelMediaAutoPlayEnable") != 0 &&
gSavedSettings.getBOOL("MediaTentativeAutoPlay"));
}
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index bea024e952..03d97a3a72 100644
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -76,7 +76,6 @@ class LLViewerMedia
public:
// String to get/set media autoplay in gSavedSettings
- static const char* AUTO_PLAY_MEDIA_SETTING;
static const char* SHOW_MEDIA_ON_OTHERS_SETTING;
static const char* SHOW_MEDIA_WITHIN_PARCEL_SETTING;
static const char* SHOW_MEDIA_OUTSIDE_PARCEL_SETTING;
diff --git a/indra/newview/llviewerparcelaskplay.cpp b/indra/newview/llviewerparcelaskplay.cpp
new file mode 100644
index 0000000000..d4aa783f12
--- /dev/null
+++ b/indra/newview/llviewerparcelaskplay.cpp
@@ -0,0 +1,301 @@
+/**
+ * @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()
+{
+ 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
+ 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();
+ }
+}
+
diff --git a/indra/newview/llviewerparcelaskplay.h b/indra/newview/llviewerparcelaskplay.h
new file mode 100644
index 0000000000..dc711917d2
--- /dev/null
+++ b/indra/newview/llviewerparcelaskplay.h
@@ -0,0 +1,89 @@
+/**
+ * @file llviewerparcelaskplay.h
+ * @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$
+ */
+
+#ifndef LLVIEWERPARCELASKPLAY_H
+#define LLVIEWERPARCELASKPLAY_H
+
+#include "llnotificationptr.h"
+#include "lluuid.h"
+
+class LLViewerParcelAskPlay : public LLSingleton<LLViewerParcelAskPlay>
+{
+ LLSINGLETON(LLViewerParcelAskPlay);
+ ~LLViewerParcelAskPlay();
+ void initSingleton();
+ void cleanupSingleton();
+public:
+ // functor expects functor(region_id, parcel_id, url, play/stop)
+ typedef boost::function<void(const LLUUID&, const S32&, const std::string&, const bool&)> ask_callback;
+ void askToPlay(const LLUUID &region_id, const S32 &parcel_id, const std::string &url, ask_callback cb);
+ void cancelNotification();
+
+ void resetCurrentParcelSetting();
+ void resetSetting(const LLUUID &region_id, const S32 &parcel_id);
+ static void resetSettings();
+
+ void loadSettings();
+ void saveSettings();
+
+ S32 hasData() { return !mRegionMap.empty(); } // subsitution for 'isInitialized'
+
+private:
+ enum EAskPlayMode{
+ ASK_PLAY_IGNORE = 0,
+ ASK_PLAY_PLAY,
+ ASK_PLAY_ASK
+ };
+
+ class ParcelData
+ {
+ public:
+ LLDate mDate;
+ EAskPlayMode mMode;
+ };
+
+ void setSetting(const LLUUID &region_id, const S32 &parcel_id, const ParcelData &data);
+ ParcelData* getSetting(const LLUUID &region_id, const S32 &parcel_id);
+ EAskPlayMode getPlayMode(const LLUUID &region_id, const S32 &parcel_id);
+ void setPlayMode(const LLUUID &region_id, const S32 &parcel_id, EAskPlayMode);
+
+ static void onAskPlayResponse(const LLSD& notification, const LLSD& response, ask_callback cb);
+
+ static std::string getAskPlayFilename();
+
+private:
+ // Variables
+
+ typedef std::map<S32, ParcelData> parcel_data_map_t;
+ typedef std::map<LLUUID, parcel_data_map_t> region_map_t;
+ region_map_t mRegionMap;
+
+ // only one notification is supposed to exists and be visible
+ LLNotificationPtr pNotification;
+};
+
+
+#endif // LLVIEWERPARCELASKPLAY_H
diff --git a/indra/newview/llviewerparcelmediaautoplay.cpp b/indra/newview/llviewerparcelmediaautoplay.cpp
index 57ee583eae..b4dc6932be 100644
--- a/indra/newview/llviewerparcelmediaautoplay.cpp
+++ b/indra/newview/llviewerparcelmediaautoplay.cpp
@@ -24,17 +24,20 @@
* $/LicenseInfo$
*/
+
#include "llviewerprecompiledheaders.h"
+
#include "llviewerparcelmediaautoplay.h"
-#include "llviewerparcelmedia.h"
+
+#include "llparcel.h"
#include "llviewercontrol.h"
#include "llviewermedia.h"
-#include "llviewerregion.h"
-#include "llparcel.h"
+#include "llviewerparcelaskplay.h"
+#include "llviewerparcelmedia.h"
#include "llviewerparcelmgr.h"
-#include "lluuid.h"
-#include "message.h"
+#include "llviewerregion.h"
#include "llviewertexturelist.h" // for texture stats
+#include "message.h"
#include "llagent.h"
#include "llmimetypes.h"
@@ -141,11 +144,28 @@ BOOL LLViewerParcelMediaAutoPlay::tick()
{
if (this_parcel)
{
- if (gSavedSettings.getBOOL("ParcelMediaAutoPlayEnable"))
+ static LLCachedControl<S32> autoplay_mode(gSavedSettings, "ParcelMediaAutoPlayEnable");
+
+ switch (autoplay_mode())
{
- // and last but not least, only play when autoplay is enabled
- LLViewerParcelMedia::play(this_parcel);
- }
+ case 0:
+ // Disabled
+ break;
+ case 1:
+ // Play, default value for ParcelMediaAutoPlayEnable
+ LLViewerParcelMedia::play(this_parcel);
+ break;
+ case 2:
+ default:
+ {
+ // Ask
+ LLViewerParcelAskPlay::getInstance()->askToPlay(this_region->getRegionID(),
+ this_parcel->getLocalID(),
+ this_parcel->getMediaURL(),
+ onStartMusicResponse);
+ break;
+ }
+ }
}
mPlayed = TRUE;
@@ -158,5 +178,18 @@ BOOL LLViewerParcelMediaAutoPlay::tick()
return FALSE; // continue ticking forever please.
}
-
+//static
+void LLViewerParcelMediaAutoPlay::onStartMusicResponse(const LLUUID &region_id, const S32 &parcel_id, const std::string &url, const bool &play)
+{
+ if (play)
+ {
+ LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+
+ // make sure we are still there
+ if (parcel->getLocalID() == parcel_id && gAgent.getRegion()->getRegionID() == region_id)
+ {
+ LLViewerParcelMedia::play(parcel);
+ }
+ }
+}
diff --git a/indra/newview/llviewerparcelmediaautoplay.h b/indra/newview/llviewerparcelmediaautoplay.h
index a052362829..a404f60da1 100644
--- a/indra/newview/llviewerparcelmediaautoplay.h
+++ b/indra/newview/llviewerparcelmediaautoplay.h
@@ -41,6 +41,9 @@ class LLViewerParcelMediaAutoPlay : LLEventTimer
static void playStarted();
private:
+ static void onStartMusicResponse(const LLUUID &region_id, const S32 &parcel_id, const std::string &url, const bool &play);
+
+ private:
S32 mLastParcelID;
LLUUID mLastRegionID;
BOOL mPlayed;
diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp
index 416d5d8e2e..86cdf96e21 100644
--- a/indra/newview/llviewerparcelmgr.cpp
+++ b/indra/newview/llviewerparcelmgr.cpp
@@ -42,6 +42,7 @@
// Viewer includes
#include "llagent.h"
#include "llagentaccess.h"
+#include "llviewerparcelaskplay.h"
#include "llviewerwindow.h"
#include "llviewercontrol.h"
//#include "llfirstuse.h"
@@ -1832,6 +1833,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use
// Only update stream if parcel changed (recreated) or music is playing (enabled)
if (!agent_parcel_update || gSavedSettings.getBOOL("MediaTentativeAutoPlay"))
{
+ LLViewerParcelAskPlay::getInstance()->cancelNotification();
std::string music_url_raw = parcel->getMusicURL();
// Trim off whitespace from front and back
@@ -1843,7 +1845,8 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use
{
if (music_url.substr(0, 7) == "http://")
{
- optionally_start_music(music_url);
+ LLViewerRegion *region = LLWorld::getInstance()->getRegion(msg->getSender());
+ optionally_start_music(music_url, parcel->mLocalID, region->getRegionID());
}
else
{
@@ -1864,25 +1867,61 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use
else
{
// Public land has no music
+ LLViewerParcelAskPlay::getInstance()->cancelNotification();
LLViewerAudio::getInstance()->stopInternetStreamWithAutoFade();
}
}//if gAudiop
};
}
-void LLViewerParcelMgr::optionally_start_music(const std::string& music_url)
+//static
+void LLViewerParcelMgr::onStartMusicResponse(const LLUUID &region_id, const S32 &parcel_id, const std::string &url, const bool &play)
{
- if (gSavedSettings.getBOOL("AudioStreamingMusic"))
+ if (play)
+ {
+ LL_INFOS("ParcelMgr") << "Starting parcel music " << url << LL_ENDL;
+ LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(url);
+ }
+}
+
+void LLViewerParcelMgr::optionally_start_music(const std::string &music_url, const S32 &local_id, const LLUUID &region_id)
+{
+ static LLCachedControl<bool> streaming_music(gSavedSettings, "AudioStreamingMusic", true);
+ if (streaming_music)
{
+ static LLCachedControl<S32> autoplay_mode(gSavedSettings, "ParcelMediaAutoPlayEnable", 1);
+ static LLCachedControl<bool> tentative_autoplay(gSavedSettings, "MediaTentativeAutoPlay", true);
// only play music when you enter a new parcel if the UI control for this
// was not *explicitly* stopped by the user. (part of SL-4878)
LLPanelNearByMedia* nearby_media_panel = gStatusBar->getNearbyMediaPanel();
- if ((nearby_media_panel &&
- nearby_media_panel->getParcelAudioAutoStart()) ||
- // or they have expressed no opinion in the UI, but have autoplay on...
- (!nearby_media_panel &&
- gSavedSettings.getBOOL(LLViewerMedia::AUTO_PLAY_MEDIA_SETTING) &&
- gSavedSettings.getBOOL("MediaTentativeAutoPlay")))
+
+ // ask mode //todo constants
+ if (autoplay_mode == 2)
+ {
+ // stop previous stream
+ LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null);
+
+ // if user set media to play - ask
+ if ((nearby_media_panel && nearby_media_panel->getParcelAudioAutoStart())
+ || (!nearby_media_panel && tentative_autoplay))
+ {
+ LLViewerParcelAskPlay::getInstance()->askToPlay(region_id,
+ local_id,
+ music_url,
+ onStartMusicResponse);
+ }
+ else
+ {
+ LLViewerParcelAskPlay::getInstance()->cancelNotification();
+ }
+ }
+ // autoplay
+ else if ((nearby_media_panel
+ && nearby_media_panel->getParcelAudioAutoStart())
+ // or they have expressed no opinion in the UI, but have autoplay on...
+ || (!nearby_media_panel
+ && autoplay_mode == 1
+ && tentative_autoplay))
{
LL_INFOS("ParcelMgr") << "Starting parcel music " << music_url << LL_ENDL;
LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(music_url);
diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h
index 29219843c9..288077fafc 100644
--- a/indra/newview/llviewerparcelmgr.h
+++ b/indra/newview/llviewerparcelmgr.h
@@ -268,7 +268,8 @@ public:
// *NOTE: Taken out 2005-03-21. Phoenix.
//void makeLandmarkAtSelection();
- static void optionally_start_music(const std::string& music_url);
+ static void onStartMusicResponse(const LLUUID &region_id, const S32 &parcel_id, const std::string &url, const bool &play);
+ static void optionally_start_music(const std::string &music_url, const S32 &local_id, const LLUUID &region_id);
static void processParcelOverlay(LLMessageSystem *msg, void **user_data);
static void processParcelProperties(LLMessageSystem *msg, void **user_data);
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 874fbe19fd..a757a4beaa 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -6057,6 +6057,34 @@ Would you like to turn off Do Not Disturb before completing this transaction?
</notification>
<notification
+ icon="notify.tga"
+ label="Parcel is Playing Media"
+ name="ParcelPlayingMedia"
+ persist="false"
+ type="notify">
+This land has media:
+[URL]
+Would you like to play it?
+ <tag>confirm</tag>
+ <form name="form">
+ <ignore name="ignore"
+ checkbox_only="true"
+ text="Always choose this option for this land."/>
+ <button
+ ignore="Play Media"
+ index="1"
+ name="Yes"
+ text="Play"/>
+ <button
+ default="true"
+ ignore="Ignore Media"
+ index="0"
+ name="No"
+ text="Ignore"/>
+ </form>
+ </notification>
+
+ <notification
icon="alertmodal.tga"
name="ConfirmDeleteProtectedCategory"
type="alertmodal">
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
index 649403184d..90f2ca2713 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
@@ -322,17 +322,40 @@
name="enable_voice_check"
width="110"/>
<!-- -->
- <check_box
- name="media_auto_play_btn"
- control_name="ParcelMediaAutoPlayEnable"
- enabled_control="AudioStreamingMedia"
- value="true"
- follows="left|bottom|right"
- height="15"
- tool_tip="Check this to let media auto-play if it wants"
- label="Allow Media to auto-play"
- top_pad="1"
- left="25"/>
+ <text
+ follows="left|top"
+ layout="topleft"
+ height="15"
+ left="0"
+ top_pad="3"
+ width="120"
+ halign="right"
+ name="media_autoplay_label">
+ Media auto-play
+ </text>
+ <combo_box
+ control_name="ParcelMediaAutoPlayEnable"
+ enabled_control="AudioStreamingMedia"
+ follows="left|top"
+ layout="topleft"
+ height="23"
+ left_pad="7"
+ top_delta="-4"
+ name="media_auto_play_combo"
+ width="100">
+ <item
+ label="Disabled"
+ name="autoplay_disabled"
+ value="0"/>
+ <item
+ label="Enabled"
+ name="autoplay_enabled"
+ value="1"/>
+ <item
+ label="Ask"
+ name="autoplay_ask"
+ value="2"/>
+ </combo_box>
<check_box
name="media_show_on_others_btn"
control_name="MediaShowOnOthers"