Show new chat message notification

This commit is contained in:
James Allen 2014-07-17 11:05:08 +01:00
parent 596ad4cf1c
commit c6f51cf5ac
8 changed files with 169 additions and 16 deletions

View file

@ -12,7 +12,9 @@ aside.chat(
.loading(ng-show="chat.loading")
i.fa.fa-fw.fa-spin.fa-refresh
| Loading...
ul.list-unstyled
ul.list-unstyled(
ng-click="resetUnreadMessages()"
)
li.message(
ng-repeat="message in chat.messages"
ng-controller="ChatMessageController"
@ -34,6 +36,11 @@ aside.chat(
p(ng-repeat="content in message.contents track by $index") {{ content }}
.new-message
textarea(placeholder="Your message...", on-enter="sendMessage()", ng-model="newMessageContent")
textarea(
placeholder="Your message...",
on-enter="sendMessage()",
ng-model="newMessageContent",
ng-click="resetUnreadMessages()"
)

View file

@ -64,4 +64,9 @@ header.toolbar.toolbar-header(ng-cloak, ng-hide="state.loading")
ng-click="toggleChat()",
ng-controller="ChatButtonController"
)
i.fa.fa-fw.fa-comment
i.fa.fa-fw.fa-comment(
ng-class="{ 'bounce': unreadMessages > 0 }"
)
span.label.label-info(
ng-show="unreadMessages > 0"
) {{ unreadMessages }}

View file

@ -1,7 +1,46 @@
define [
"base"
], (App) ->
App.controller "ChatButtonController", ["$scope", ($scope) ->
App.controller "ChatButtonController", ($scope, ide) ->
$scope.toggleChat = () ->
$scope.ui.chatOpen = !$scope.ui.chatOpen
]
$scope.resetUnreadMessages()
$scope.unreadMessages = 0
$scope.resetUnreadMessages = () ->
$scope.unreadMessages = 0
$scope.$on "chat:resetUnreadMessages", (e) ->
$scope.resetUnreadMessages()
$scope.$on "chat:newMessage", (e, message) ->
if message?
if message.user.id != ide.$scope.user.id
if !$scope.ui.chatOpen
$scope.unreadMessages += 1
flashTitle()
focussed = true
newMessageNotificationTimeout = null
originalTitle = null
$(window).on "focus", () ->
clearNewMessageNotification()
focussed = true
$(window).on "blur", () ->
focussed = false
flashTitle = () ->
if !focussed and !newMessageNotificationTimeout?
originalTitle ||= window.document.title
do changeTitle = () =>
if window.document.title == originalTitle
window.document.title = "New Message"
else
window.document.title = originalTitle
newMessageNotificationTimeout = setTimeout changeTitle, 800
clearNewMessageNotification = () ->
clearTimeout newMessageNotificationTimeout
newMessageNotificationTimeout = null
if originalTitle?
window.document.title = originalTitle

View file

@ -2,7 +2,7 @@ define [
"base"
"ide/chat/services/chatMessages"
], (App) ->
App.controller "ChatController", ($scope, chatMessages, @ide, $location) ->
App.controller "ChatController", ($scope, chatMessages, ide, $location) ->
$scope.chat = chatMessages.state
$scope.$watch "chat.messages", (messages) ->
@ -12,6 +12,13 @@ define [
$scope.$on "layout:chat:resize", () ->
$scope.$emit "updateScrollPosition"
$scope.$watch "chat.newMessage", (message) ->
if message?
ide.$scope.$broadcast "chat:newMessage", message
$scope.resetUnreadMessages = () ->
ide.$scope.$broadcast "chat:resetUnreadMessages"
$scope.sendMessage = ->
chatMessages

View file

@ -12,10 +12,13 @@ define [
loading: false
atEnd: false
nextBeforeTimestamp: null
newMessage: null
}
ide.socket.on "new-chat-message", (message) =>
appendMessage(message)
ide.$scope.$apply () ->
chat.state.newMessage = message
appendMessage(message)
chat.loadMoreMessages = () ->
return if chat.state.atEnd

View file

@ -12,4 +12,89 @@
img {
margin-top: -10px;
}
}
}
@-webkit-keyframes bounce {
0%, 10%, 26%, 40%, 50% {
-webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
-webkit-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
}
20%, 21% {
-webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
-webkit-transform: translate3d(0, -10px, 0);
transform: translate3d(0, -10px, 0);
}
35% {
-webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
-webkit-transform: translate3d(0, -5px, 0);
transform: translate3d(0, -5px, 0);
}
45% {
-webkit-transform: translate3d(0,-2px,0);
transform: translate3d(0,-2px,0);
}
50% {
-webkit-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
}
}
@keyframes bounce {
0%, 10%, 26%, 40%, 50% {
-webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
-webkit-transform: translate3d(0,0,0);
-ms-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
}
20%, 21% {
-webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
-webkit-transform: translate3d(0, -10px, 0);
-ms-transform: translate3d(0, -10px, 0);
transform: translate3d(0, -10px, 0);
}
35% {
-webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
-webkit-transform: translate3d(0, -5px, 0);
-ms-transform: translate3d(0, -5px, 0);
transform: translate3d(0, -5px, 0);
}
45% {
-webkit-transform: translate3d(0,-2px,0);
-ms-transform: translate3d(0,-2px,0);
transform: translate3d(0,-2px,0);
}
50% {
-webkit-transform: translate3d(0,0,0);
-ms-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
}
}
.bounce {
-webkit-animation-duration: 2s;
animation-duration: 2s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
-webkit-animation-name: bounce;
animation-name: bounce;
-webkit-transform-origin: center bottom;
-ms-transform-origin: center bottom;
transform-origin: center bottom;
}

View file

@ -75,14 +75,6 @@
.toolbar {
.log-btn {
position: relative;
.label {
position: absolute;
top: 0;
right: 0;
padding: .15em .6em .2em;
font-size: 60%;
}
&.active, &:active {
.label {
display: none;

View file

@ -2,6 +2,17 @@
height: 40px;
border-bottom: 1px solid @toolbar-border-color;
a {
position: relative;
.label {
position: absolute;
top: 0;
right: 0;
padding: .15em .6em .2em;
font-size: 60%;
}
}
a:not(.btn) {
display: inline-block;
color: @gray-light;
@ -32,6 +43,10 @@
background-color: @link-color;
.box-shadow(inset 0 3px 5px rgba(0, 0, 0, 0.225));
}
.label {
top: 4px;
right: 4px;
}
}
.toolbar-right {