Skip to content

Commit

Permalink
Merge pull request #237 from lewisl9029/feature/notification-center
Browse files Browse the repository at this point in the history
Feature notification center. Closes #223
  • Loading branch information
lewisl9029 committed Aug 21, 2015
2 parents f2b77fa + 25e75c7 commit c6bd9ae
Show file tree
Hide file tree
Showing 21 changed files with 143 additions and 74 deletions.
2 changes: 1 addition & 1 deletion app/app-menu.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@
<ion-nav-view></ion-nav-view>
</ion-side-menu-content>
<ion-side-menu side="left" expose-aside-when="large">
<toc-side-menu></toc-side-menu>
<toc-conversations-menu></toc-conversations-menu>
</ion-side-menu>
</ion-side-menus>
4 changes: 2 additions & 2 deletions app/components/channel-list/channel-list-directive.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ export default /*@ngInject*/ function tocChannelList() {
});
}

return navigation.goFromMenu(channel.channelInfo.id);
return navigation.navigate(channel.channelInfo.id);
};

this.goToChannel = function goToChannel(channelId) {
return navigation.goFromMenu(channelId);
return navigation.navigate(channelId);
};
}
};
Expand Down
6 changes: 4 additions & 2 deletions app/components/components.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import cloudConnectForm from './cloud-connect-form/cloud-connect-form';
import cloudManageForm from './cloud-manage-form/cloud-manage-form';
import messageList from './message-list/message-list';
import notificationCard from './notification-card/notification-card';
import notificationList from './notification-list/notification-list';
import qrImage from './qr-image/qr-image';
import sideMenu from './side-menu/side-menu';
import conversationsMenu from './conversations-menu/conversations-menu';
import signinForm from './signin-form/signin-form';
import signupForm from './signup-form/signup-form';
import spinnerButton from './spinner-button/spinner-button';
Expand All @@ -22,8 +23,9 @@ export default angular.module('toc.components', [
cloudManageForm.name,
messageList.name,
notificationCard.name,
notificationList.name,
qrImage.name,
sideMenu.name,
conversationsMenu.name,
signinForm.name,
signupForm.name,
spinnerButton.name,
Expand Down
2 changes: 1 addition & 1 deletion app/components/components.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@import 'channel-card/channel-card';
@import 'channel-list/channel-list';
@import 'message-list/message-list';
@import 'side-menu/side-menu';
@import 'conversations-menu/conversations-menu';
@import 'spinner-button/spinner-button';
@import 'user-card/user-card';
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import template from './side-menu.html!text';
import template from './conversations-menu.html!text';

export let directiveName = 'tocSideMenu';
export default /*@ngInject*/ function tocSideMenu() {
export let directiveName = 'tocConversationsMenu';
export default /*@ngInject*/ function tocConversationsMenu() {
return {
restrict: 'E',
template: template,
controllerAs: 'sideMenu',
controller: /*@ngInject*/ function SideMenuController(
controllerAs: 'conversationsMenu',
controller: /*@ngInject*/ function ConversationsMenuController(
$ionicPopup,
$q,
$scope,
Expand All @@ -22,7 +22,7 @@ export default /*@ngInject*/ function tocSideMenu() {
state.addListener(viewIdCursor, updateViewId, $scope);

this.goToHome = function goToHome() {
return navigation.goFromMenu('home');
return navigation.navigate('home');
};

let invite = (invitePopup) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<ion-header-bar class="bar-positive">
<h1 class="title">Conversations</h1>
</ion-header-bar>
<div class="toc-side-menu-subheader bar bar-subheader">
<div class="toc-conversations-menu-subheader bar bar-subheader">
<toc-user-card
ng-class="{'toc-active-view': sideMenu.viewId === 'home'}"
ng-click="sideMenu.goToHome()" menu-close></toc-user-card>
ng-class="{'toc-active-view': conversationsMenu.viewId === 'home'}"
ng-click="conversationsMenu.goToHome()" menu-close></toc-user-card>
</div>
<ion-content class="has-subheader">
<toc-channel-list>
Expand All @@ -13,8 +13,8 @@ <h1 class="title">Conversations</h1>
<ion-footer-bar>
<div class="col">
<button class="button button-block button-outline button-balanced"
ng-click="sideMenu.openInvitePopup()">
Add a new contact
ng-click="conversationsMenu.openInvitePopup()">
Start a conversation
</button>
</div>
</ion-footer-bar>
6 changes: 6 additions & 0 deletions app/components/conversations-menu/conversations-menu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import angular from 'angular';

import directive, { directiveName } from './conversations-menu-directive';

export default angular.module('toc.components.conversations-menu', [])
.directive(directiveName, directive);
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.toc-side-menu-subheader {
.toc-conversations-menu-subheader {
z-index: 11; //needed because menu content is set to 10
}

Expand Down
56 changes: 29 additions & 27 deletions app/components/message-list/message-list-directive.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export let directiveName = 'tocMessageList';
export default /*@ngInject*/ function tocMessageList(
$interval,
$ionicScrollDelegate,
notifications,
R,
state
) {
Expand All @@ -19,7 +20,22 @@ export default /*@ngInject*/ function tocMessageList(
let messagesCursor = state.cloud.messages
.select([scope.channelId]);

$ionicScrollDelegate.scrollBottom(false);
let viewingLatestCursor = channelCursor.select(['viewingLatest']);
let scrollToLatest = () => {
if (!viewingLatestCursor.get()) {
return;
}

if (state.cloud.navigation.get('activeViewId') !== scope.channelId) {
return;
}

$ionicScrollDelegate.scrollBottom(true);
notifications.dismiss(scope.channelId)
.then(() => state.save(channelCursor, ['unreadMessageId'], null));
};

state.addListener(viewingLatestCursor, scrollToLatest, scope);

let updateMessageListPosition = () => {
let scrollView = $ionicScrollDelegate.getScrollView();
Expand All @@ -28,20 +44,18 @@ export default /*@ngInject*/ function tocMessageList(
return;
}

$ionicScrollDelegate.scrollBottom(true);

state.save(
channelCursor,
['unreadMessageId'],
null
);
state.save(channelCursor, ['viewingLatest'], true)
.then(() => state.save(channelCursor, ['unreadMessageId'], null));
};

state.addListener(messagesCursor, updateMessageListPosition, scope, {
skipInitialize: true
});

$interval(() => {
if (state.cloud.navigation.get('activeViewId') !== scope.channelId) {
return;
}
//Updates unread messages if scrolled to bottom
//TODO: write a more robust version that moves unread marker granularly
let scrollView = $ionicScrollDelegate.getScrollView();
Expand All @@ -52,28 +66,20 @@ export default /*@ngInject*/ function tocMessageList(
return;
}

return state.save(
channelCursor,
['viewingLatest'],
false
);
return state.save(channelCursor, ['viewingLatest'], false);
}

//Otherwise update unread pointer
if (!channelCursor.get(['viewingLatest'])) {
state.save(
channelCursor,
['viewingLatest'],
true
);
state.save(channelCursor, ['viewingLatest'], true);
}

if (channelCursor.get(['unreadMessageId'])) {
state.save(
channelCursor,
['unreadMessageId'],
null
);
state.save(channelCursor, ['unreadMessageId'], null);
}

if (!notifications.isDismissed(scope.channelId)) {
notifications.dismiss(scope.channelId);
}
}, 5000);
},
Expand Down Expand Up @@ -112,10 +118,6 @@ export default /*@ngInject*/ function tocMessageList(

state.addListener(messagesCursor, updateMessages, $scope);

this.getMessageOrder = (message) => {
return
};

this.isUnread = (message) => {
let unreadMessageId = state.cloud.channels
.get([this.channelId, 'unreadMessageId']);
Expand Down
3 changes: 2 additions & 1 deletion app/components/message-list/message-list.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
height: 3px;
text-align: left;
color: $assertive;
box-shadow: 0 1px 2px $assertive inset;
//FIXME: pick a less jarring unread marker style
// box-shadow: 0 1px 2px $assertive inset;
font-size: 10px;
width: 110%;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default /*@ngInject*/ function tocNotificationCard() {
controller: /*@ngInject*/ function NotificationCardController(
$scope,
identity,
navigation,
state
) {
//TODO: reduce volume of update events in other services
Expand All @@ -22,11 +23,11 @@ export default /*@ngInject*/ function tocNotificationCard() {
let channelCursor = state.cloud.channels.select([channelId]);

this.click = () => {
//TODO: scroll down to bottom of message list after navigating
return navigation.go('channel', { channelId });
return navigation.navigate(channelId)
.then(() => state.save(channelCursor, ['viewingLatest'], true));
};

let messageIdCursor = channelCursor.select(['unreadMessageId']);
let messageIdCursor = channelCursor.select(['latestMessageId']);
let updateMessage = () => {
let messageId = messageIdCursor.get();
if (!messageId) {
Expand Down
26 changes: 26 additions & 0 deletions app/components/notification-list/notification-list-directive.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import template from './notification-list.html!text';

export let directiveName = 'tocNotificationList';
export default /*@ngInject*/ function tocNotificationList() {
return {
restrict: 'E',
template: template,
controllerAs: 'notificationList',
controller: /*@ngInject*/ function NotificationListController(
$scope,
identity,
navigation,
state,
R
) {
let notificationsCursor = state.cloud.notifications;
let updateNotifications = () => {
this.notifications = R.pipe(
R.values,
R.reject(R.prop('dismissed'))
)(notificationsCursor.get() || {});
};
state.addListener(notificationsCursor, updateNotifications, $scope);
}
};
}
6 changes: 6 additions & 0 deletions app/components/notification-list/notification-list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<ion-list>
<toc-notification-card
notification-id="{{::notification.notificationInfo.id}}"
ng-repeat="notification in notificationList.notifications track by notification.notificationInfo.id">
</toc-notification-card>
</ion-list>
6 changes: 6 additions & 0 deletions app/components/notification-list/notification-list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import angular from 'angular';

import directive, { directiveName } from './notification-list-directive';

export default angular.module('toc.components.notification-list', [])
.directive(directiveName, directive);
6 changes: 0 additions & 6 deletions app/components/side-menu/side-menu.js

This file was deleted.

5 changes: 4 additions & 1 deletion app/components/user-card/user-card-directive.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ export default /*@ngInject*/ function tocUserCard(

let notificationsCursor = state.cloud.notifications;
let updateSummary = () => {
let notificationCount = R.keys(notificationsCursor.get()).length;
let notificationCount = R.pipe(
R.values,
R.reject(R.prop('dismissed'))
)(notificationsCursor.get() || {}).length;

if (notificationCount === 0) {
this.summary = 'No new notifications';
Expand Down
22 changes: 14 additions & 8 deletions app/services/navigation/navigation-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,18 @@ export default /*@ngInject*/ function navigation(
return $state.go(stateName, parameters);
};

let goFromMenu = function goFromMenu(viewId) {
let destination = viewId === 'home' ?
let navigate = function navigate(viewId) {
if (isActiveView(viewId)) {
return $q.when();
}

let toHome = viewId === 'home';
let destination = toHome ?
app.private.home : app.private.channel;

let destinationParams = viewId === 'home' ?
let destinationParams = toHome ?
undefined : { channelId: viewId };

if (at(destination, destinationParams)) {
return $q.when();
}

$ionicHistory.nextViewOptions({
disableBack: true,
disableAnimate: false
Expand All @@ -52,6 +53,10 @@ export default /*@ngInject*/ function navigation(
));
};

let isActiveView = function isActiveView(viewId) {
return state.cloud.navigation.get('activeViewId') === viewId;
};

let at = function at(stateName, parameters) {
return $state.is(stateName, parameters);
};
Expand Down Expand Up @@ -129,7 +134,8 @@ export default /*@ngInject*/ function navigation(
return {
app,
go,
goFromMenu,
navigate,
isActiveView,
at,
isPrivateState,
clearCache,
Expand Down
4 changes: 1 addition & 3 deletions app/services/network/network-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,7 @@ export default /*@ngInject*/ function network(
$q.when();

return updatingUnreadPointer
.then(() => notifications.notify(
messageId
));
.then(() => notifications.notify(channelId));
});
};

Expand Down
Loading

0 comments on commit c6bd9ae

Please sign in to comment.