Skip to content
This repository has been archived by the owner on Feb 14, 2023. It is now read-only.

Commit

Permalink
Merge pull request #275 from HabitRPG/paglias/notifications
Browse files Browse the repository at this point in the history
Notifications overhaul
  • Loading branch information
paglias committed Oct 1, 2014
2 parents fb550cb + 2dcea77 commit f7c1aff
Show file tree
Hide file tree
Showing 7 changed files with 247 additions and 91 deletions.
1 change: 1 addition & 0 deletions gulpfile.js
Expand Up @@ -54,6 +54,7 @@ var paths = {
'scripts/controllers/mountDetailsCtrl.js',
'scripts/controllers/stableCtrl.js',
'scripts/controllers/partyCtrl.js',
'scripts/controllers/notificationCtrl.js',
'scripts/controllers/guildCtrl.js'
],
copy: [
Expand Down
49 changes: 47 additions & 2 deletions scripts/app.js
Expand Up @@ -21,7 +21,7 @@ var habitrpg = angular.module('habitrpg', ['ionic', 'userServices', 'authService
.constant("STORAGE_SETTINGS_ID", 'habit-mobile-settings')
.constant("MOBILE_APP", true)

.config(['$stateProvider', '$urlRouterProvider', function ($stateProvider, $urlRouterProvider) {
.config(['$stateProvider', '$urlRouterProvider', '$provide', '$httpProvider', function ($stateProvider, $urlRouterProvider, $provide, $httpProvider) {
$urlRouterProvider
.when('/app', '/app/tasks/habits')
.when('/app/tasks', '/app/tasks/habits')
Expand Down Expand Up @@ -276,5 +276,50 @@ var habitrpg = angular.module('habitrpg', ['ionic', 'userServices', 'authService
data: {sync: true},
templateUrl: 'views/app.guilds.public.html',
controller: 'GuildPublicCtrl'
})
});

$provide.factory('myHttpInterceptor', ['$rootScope','$q',function($rootScope,$q) {
return {
response: function(response) {
return response;
},
responseError: function(response) {
// Offline
if (response.status == 0 ||
// don't know why we're getting 404 here, should be 0
(response.status == 404 && _.isEmpty(response.data))) {
// Don't do anything in mobile

// Needs refresh
} else if (response.needRefresh) {
// Don't do anything in mobile (for now)
} else if (response.data.code && response.data.code === 'ACCOUNT_SUSPENDED') {
alert(response.data.err)
localStorage.clear();
location.reload();

// 400 range?
} else if (response.status < 500) {
$rootScope.$broadcast('responseText', response.data.err || response.data);
// Need to reject the prompse so the error is handled correctly
if (response.status === 401) {
return $q.reject(response);
}

// Error
} else {
var error = 'Error contacting the server. Please try again in a few minutes.';
$rootScope.$broadcast('responseError', error);
console.error(response);
}

return response;
// this completely halts the chain, meaning we can't queue offline actions
//if (canRecover(response)) return responseOrNewPromise
//return $q.reject(response);
}
};
}]);
$httpProvider.interceptors.push('myHttpInterceptor');

}])
135 changes: 135 additions & 0 deletions scripts/controllers/notificationCtrl.js
@@ -0,0 +1,135 @@
'use strict';

habitrpg.controller('NotificationCtrl',
['$scope', '$rootScope', 'User', 'Notification',
function ($scope, $rootScope, User, Notification) {

var alreadyNotified = {
hp: null,
gp: null,
exp: null,
mp: null
};

$rootScope.$watchGroup([
'user.stats.hp',
'user.stats.exp',
'user.stats.gp',
'user.stats.mp'
], function(nv, ov){
var stats = {hp: null, exp: null, gp: null, mp: null};

if(nv[0] !== ov[0] && User.user.stats.lvl != 0 && alreadyNotified.hp != nv[0]){
stats.hp = (nv[0] - ov[0]);
alreadyNotified.hp = nv[0];
}

if(nv[1] !== ov[1] && User.user.stats.lvl != 0 && alreadyNotified.exp != nv[1]){
stats.exp = (nv[1] - ov[1]);
alreadyNotified.exp = nv[1];
}

if(nv[2] !== ov[2] && alreadyNotified.gp != nv[2]){
stats.gp = (nv[2] - ov[2]);
alreadyNotified.gp = nv[2];
}

if(nv[3] !== ov[3] && User.user.flags.classSelected && !User.user.preferences.disableClasses && alreadyNotified.mp != nv[3]){
stats.mp = (nv[3] - ov[3]);
alreadyNotified.mp = nv[3];
}

if(stats.hp || stats.exp || stats.gp || stats.mp) Notification.push({type: 'stats', stats: stats});
});

// TODO bonus
/*$rootScope.$watch('user.stats.gp', function(after, before) {
if (after == before) return;
if (User.user.stats.lvl == 0) return;
var money = after - before;
var bonus = User.user._tmp.streakBonus;
//Notification.gp(money, bonus || 0);
Notification.push({type: 'text', text: ('money now: ' + (money) + ' ' + bonus)});
//Append Bonus
if ((money > 0) && !!bonus) {
if (bonus < 0.01) bonus = 0.01;
Notification.push({type: 'text', text: ('bonus: ' + (bonus))});
//Notification.text("+ " + Notification.coins(bonus) + ' ' + window.env.t('streakCoins'));
delete User.user._tmp.streakBonus;
}
});*/

$rootScope.$watch('user._tmp.crit', function(after, before){
if (after == before || !after) return;
var amount = User.user._tmp.crit * 100 - 100;
// reset the crit counter
User.user._tmp.crit = undefined;
// Website use icon glyphicon-certificate, slightly different
Notification.push({type: 'text', text: '<i class="ion-load-b"></i>&nbsp;' + env.t('critBonus') + Math.round(amount) + '%'});
});

// TODO: text and icon glyphicon-gift
$rootScope.$watch('user._tmp.drop', function(after, before){
if (after == before || !after) return;
if (after.type !== 'gear') {
var type = (after.type == 'Food') ? 'food' :
(after.type == 'HatchingPotion') ? 'hatchingPotions' : // can we use camelcase and remove this line?
(after.type.toLowerCase() + 's');
if(!User.user.items[type][after.key]){
User.user.items[type][after.key] = 0;
}
User.user.items[type][after.key]++;
}

if(after.type === 'HatchingPotion'){
var text = $rootScope.Content.hatchingPotions[after.key].text();
var notes = $rootScope.Content.hatchingPotions[after.key].notes();
Notification.push({type: 'text', text: '<i class="ion-cube"></i>&nbsp;' + env.t('messageDropPotion', {dropText: text, dropNotes: notes})});
}else if(after.type === 'Egg'){
var text = $rootScope.Content.eggs[after.key].text();
var notes = $rootScope.Content.eggs[after.key].notes();
Notification.push({type: 'text', text: '<i class="ion-cube"></i>&nbsp;' + env.t('messageDropEgg', {dropText: text, dropNotes: notes})});
}else if(after.type === 'Food'){
var text = $rootScope.Content.food[after.key].text();
var notes = $rootScope.Content.food[after.key].notes();
Notification.push({type: 'text', text: '<i class="ion-cube"></i>&nbsp;' + env.t('messageDropFood', {dropArticle: after.article, dropText: text, dropNotes: notes})});
}else{
// Keep support for another type of drops that might be added
Notification.push({type: 'text', text: '<i class="ion-cube"></i>&nbsp;' + User.user._tmp.drop.dialog});
}
});

$rootScope.$watch('user.achievements.streak', function(after, before){
if(before == undefined || after == before || after < before) return;
Notification.push({type: 'text', text: '<i class="ion-refresh"></i>&nbsp;' + env.t('streakName') + ': ' + after});
// TODO see below
/*if (User.user.achievements.streak > 1) {
Notification.push(type: 'text', text: 'streak achievement');
Notification.streak(User.user.achievements.streak);
}
else {
//$rootScope.openModal('achievements/streak');
}*/
});

$rootScope.$watch('user.stats.lvl', function(after, before) {
if (after == before) return;
if (after > before) {
Notification.push({type: 'text', text: '<i class="ion-chevron-up"></i>&nbsp;' + env.t('levelUp')});
}
});

// TODO icon?
$rootScope.$on('responseError', function(ev, error){
Notification.push({type: 'text', text: '<i class="ion-alert"></i>&nbsp;' + error});
//Notification.error(error);
});

// TODO icon?
$rootScope.$on('responseText', function(ev, error){
Notification.push({type: 'text', text: '<i class="ion-alert"></i>&nbsp;' + error});
});

}]);
12 changes: 0 additions & 12 deletions scripts/controllers/tasksCtrl.js
Expand Up @@ -83,18 +83,6 @@ habitrpg
var statsDiff = {};
var oldStats = _.clone(User.user.stats);
User.user.ops.score({params:{id:task.id,direction:direction}});

//compute the stats change.
_.each(oldStats, function (value, key) {
var newValue = User.user.stats[key];
if (newValue !== value) {
statsDiff[key] = newValue - value;
}
});
//notify user if there are changes in stats.
if (Object.keys(statsDiff).length > 0) {
Notification.push({type: 'stats', stats: statsDiff});
}
};

$scope.notDue = function(task) {
Expand Down
62 changes: 21 additions & 41 deletions scripts/services/notificationServices.js
@@ -1,65 +1,45 @@
angular.module('notificationServices', []).
factory('Notification', ['$filter','$rootScope', '$timeout', function ($filter,$rootScope, $timeout) {

$rootScope.notification = {type:null,data:null};
var active = false;
var timer = null;
$rootScope.notifications = [];
var goldFilter = $filter('gold');
var silverFilter = $filter('silver');
var sign = function(number){
return number?number<0?'-':'+':'+';
};
var round = function(number){
return Math.abs(number.toFixed(1));
};

return {

hide: function () {
$rootScope.notification = {type:null,data:null};
active = false;
timer = null;
},

animate: function () {
if (timer) {
clearTimeout(timer);
timer = $timeout(this.hide, 2000)
}
if (active == false) {
active = true;
timer = $timeout(this.hide, 2000);
}
},

push: function (message) {
var notif = $rootScope.notification.data = {};
$rootScope.notification.type = message.type;
var notif = {data: {}};
notif.type = message.type;

switch(message.type) {
case 'stats':
if (message.stats.gp) {
notif.gp = (message.stats.exp>0 ? '+':'')+ goldFilter(message.stats.gp);
notif.silver = silverFilter(message.stats.gp);
notif.data.gp = goldFilter(message.stats.gp);
notif.data.silver = silverFilter(message.stats.gp);
}
if (message.stats.exp)
notif.exp = (message.stats.exp>0 ? '+':'')+ message.stats.exp;
notif.data.exp = sign(message.stats.exp) + round(message.stats.exp);
if (message.stats.hp)
notif.hp = message.stats.hp.toFixed(2)
notif.data.hp = sign(message.stats.hp) + round(message.stats.hp);
if (message.stats.mp)
notif.data.mp = sign(message.stats.hp) + round(message.stats.mp)
break;
case 'text':
$rootScope.notification.data = message.text;
notif.data = message.text;
break;
}

this.animate()
},

get: function () {
return data;
},

clearTimer: function () {
$timeout.cancel(timer);
timer = null;
active = false;
},
$rootScope.notifications.push(notif);

init: function () {
timer = $timeout(this.hide, 2000);
$timeout(function(){
$rootScope.notifications.shift();
}, 2500);
}

}
Expand Down
39 changes: 19 additions & 20 deletions styles/app.styl
Expand Up @@ -6,21 +6,25 @@
@import "../node_modules/habitrpg/public/css/menu"
@import "../node_modules/habitrpg/public/css/customizer"

//.notif-bar.ng-hide-add, .notif-bar.ng-hide-remove
.notif-bar.ng-hide-add
-webkit-transition:all linear 0.5s;
-moz-transition:all linear 0.5s;
-o-transition:all linear 0.5s;
transition:all linear 0.5s;
display:block!important;

.notif-bar.ng-hide-add.ng-hide-add-active,
.notif-bar.ng-hide-remove
opacity 0

.notif-bar.ng-hide-add,
.notif-bar.ng-hide-remove.ng-hide-remove-active
opacity 1
.notif-bar
.shop_gold, .shop_silver
margin-top: 8px

.notif-bar.ng-move,
.notif-bar.ng-enter,
.notif-bar.ng-leave
-webkit-transition: all linear 0.5s
transition: all linear 0.5s

.notif-bar.ng-leave.ng-leave-active,
.notif-bar.ng-move,
.notif-bar.ng-enter
opacity: 0

.notif-bar.ng-leave,
.notif-bar.ng-move.ng-move-active,
.notif-bar.ng-enter.ng-enter-active
opacity: 1

.ng-hide
opacity 0
Expand Down Expand Up @@ -116,11 +120,6 @@ for $stage in (worst $worst) (worse $worse) (bad $bad) (neutral $neutral) (good
margin: 4px 20px 4px 4px;
td {vertical-align: middle;}

.exp-and-gold
//border-left 1px solid white
//padding: 13px 0
margin: 0 8px

.muted *
color: grey !important

Expand Down

0 comments on commit f7c1aff

Please sign in to comment.