Add notification for muting with unmute option.

This adds a support a notification at the top of the screen that
alerts a user they’ve muted a stream and gives them the option to
unmute if it was an accident.

The notification disappears automatically after 4s, but if a user
moves their mouse over the notification, the timer resets to 2s after
the user moves their mouse off the notification, to make it easy for
users to read the full message and decide what to do.
This commit is contained in:
Brock Whittaker
2016-08-26 16:47:30 -07:00
committed by Tim Abbott
parent 3a4fff837f
commit c833265fae
5 changed files with 194 additions and 9 deletions

View File

@@ -16,6 +16,76 @@ exports.rerender = function () {
}
};
exports.notify_with_undo_option = (function () {
var event_added = false;
var meta = {
stream: null,
topic: null,
hide_me_time: null,
alert_hover_state: false,
$mute: null
};
var animate = {
fadeOut: function ($mute) {
if (meta.$mute) {
meta.$mute.fadeOut(500).removeClass("show");
}
},
fadeIn: function ($mute) {
if (meta.$mute) {
meta.$mute.fadeIn(500).addClass("show");
}
}
};
var interval = setInterval(function () {
if (meta.hide_me_time < new Date().getTime() && !meta.alert_hover_state) {
animate.fadeOut();
}
}, 100);
return function (stream, topic) {
var $exit = $("#unmute_muted_topic_notification .exit-me");
if (!meta.$mute) {
meta.$mute = $("#unmute_muted_topic_notification");
$exit.click(function () {
animate.fadeOut();
});
meta.$mute.find("#unmute").click(function () {
// it should reference the meta variable and not get stuck with
// a pass-by-value of stream, topic.
popovers.topic_ops.unmute(meta.stream, meta.topic);
animate.fadeOut();
});
}
meta.stream = stream;
meta.topic = topic;
// add a four second delay before closing up.
meta.hide_me_time = new Date().getTime() + 4000;
meta.$mute.find(".topic").html(topic);
meta.$mute.find(".stream").html(stream);
animate.fadeIn();
// if the user mouses over the notification, don't hide it.
meta.$mute.mouseenter(function () {
meta.alert_hover_state = true;
});
// once the user's mouse leaves the notification, restart the countdown.
meta.$mute.mouseleave(function () {
meta.alert_hover_state = false;
// add at least 2000ms but if more than that exists just keep the
// current amount.
meta.hide_me_time = Math.max(meta.hide_me_time, new Date().getTime() + 2000);
});
};
}());
exports.persist_and_rerender = function () {
// Optimistically rerender our new muting preferences. The back
// end should eventually save it, and if it doesn't, it's a recoverable

View File

@@ -136,6 +136,23 @@ exports.hide_actions_popover = function () {
}
};
exports.topic_ops = {
mute: function (stream, topic) {
popovers.hide_topic_sidebar_popover();
muting.mute_topic(stream, topic);
muting_ui.persist_and_rerender();
muting_ui.notify_with_undo_option(stream, topic);
},
// we don't run a unmute_notif function because it isn't an issue as much
// if someone accidentally unmutes a stream rather than if they mute it
// and miss out on info.
unmute: function (stream, topic) {
popovers.hide_topic_sidebar_popover();
muting.unmute_topic(stream, topic);
muting_ui.persist_and_rerender();
}
};
function message_info_popped() {
return current_message_info_popover_elem !== undefined;
}
@@ -364,9 +381,7 @@ exports.register_click_handlers = function () {
$('body').on('click', '.sidebar-popover-mute-topic', function (e) {
var stream = $(e.currentTarget).attr('data-stream-name');
var topic = $(e.currentTarget).attr('data-topic-name');
popovers.hide_topic_sidebar_popover();
muting.mute_topic(stream, topic);
muting_ui.persist_and_rerender();
exports.topic_ops.mute(stream, topic);
e.stopPropagation();
e.preventDefault();
});
@@ -374,9 +389,7 @@ exports.register_click_handlers = function () {
$('body').on('click', '.sidebar-popover-unmute-topic', function (e) {
var stream = $(e.currentTarget).attr('data-stream-name');
var topic = $(e.currentTarget).attr('data-topic-name');
popovers.hide_topic_sidebar_popover();
muting.unmute_topic(stream, topic);
muting_ui.persist_and_rerender();
exports.topic_ops.unmute(stream, topic);
e.stopPropagation();
e.preventDefault();
});
@@ -514,9 +527,7 @@ exports.register_click_handlers = function () {
$('body').on('click', '.popover_mute_topic', function (e) {
var stream = $(e.currentTarget).data('msg-stream');
var topic = $(e.currentTarget).data('msg-topic');
popovers.hide_actions_popover();
muting.mute_topic(stream, topic);
muting_ui.persist_and_rerender();
exports.topic_ops.mute(stream, topic);
e.stopPropagation();
e.preventDefault();
});

View File

@@ -42,6 +42,99 @@ a {
cursor: pointer;
}
p.n-margin {
margin: 10px 0px 0px 0px;
}
.small-line-height {
line-height: 1.1;
}
.float-left {
float: left;
}
.float-right {
float: right;
}
.float-clear {
clear: both;
}
.light {
font-weight: 300;
}
.no-margin {
margin: 0;
}
.border-radius {
border-radius: 4px;
}
#unmute_muted_topic_notification {
display: none;
position: absolute;
width: 400px;
top: 0px;
left: calc(50vw - 220px);
padding: 15px;
background-color: #FAFAFA;
border-radius: 5px;
box-shadow: 0px 0px 30px rgba(0,0,0,0.25);
z-index: 101;
animation-name: pulse;
animation-iteration-count: infinite;
animation-duration: 2s;
transition-property: top, bottom;
transition-duration: 0.5s;
}
#unmute_muted_topic_notification.show {
top: 50px;
}
#unmute_muted_topic_notification h3 {
font-size: 16pt;
margin-top: 2px;
}
@keyframes pulse {
0% {
box-shadow: 0px 0px 30px rgba(0,0,0,0.35);
}
50% {
box-shadow: 0px 0px 30px rgba(0,0,0,0.15);
}
100% {
box-shadow: 0px 0px 30px rgba(0,0,0,0.35);
}
}
#unmute_muted_topic_notification .btn {
background-color: transparent;
border: 1px solid #444;
outline: none;
transition: all 0.2s ease;
}
#unmute_muted_topic_notification .btn:hover {
background-color: #444;
color: #FAFAFA;
}
#unmute_muted_topic_notification .exit-me {
font-size: 30pt;
font-weight: 200;
margin: 5px 0px 0px 10px;
cursor: pointer;
}
.ztable_comp_col1 {
width: 10px;
}

View File

@@ -44,6 +44,8 @@ var page_params = {{ page_params }};
{{ minified_js('app_debug')|safe }}
{% endif %}
{% include "zerver/topic_is_muted.html" %}
{% endblock %}
{% block content %}
<div id="css-loading">

View File

@@ -0,0 +1,9 @@
<div id="unmute_muted_topic_notification">
<div class="float-header">
<h3 class="light no-margin small-line-height float-left">Topic Muted</h3>
<div class="exit-me float-right">&#215;</div>
<button class="btn border-radius float-right" id="unmute" type="button" name="button">Unmute</button>
<div class="float-clear"></div>
</div>
<p class="n-margin">You have muted the topic <span class="topic"></span> under the <span class="stream"></span> stream.</p>
</div>