diff --git a/customize.dist/src/less2/include/alertify.less b/customize.dist/src/less2/include/alertify.less
index 4bd5e298b..6569de99b 100644
--- a/customize.dist/src/less2/include/alertify.less
+++ b/customize.dist/src/less2/include/alertify.less
@@ -3,6 +3,7 @@
@import (reference) "./variables.less";
@import (reference) "./avatar.less";
@import (reference) "./tools.less";
+@import (reference) "./buttons.less";
.alertify_main() {
--LessLoader_require: LessLoader_currentFile();
@@ -221,28 +222,6 @@
::-ms-input-placeholder { /* Microsoft Edge */
color: @cryptpad_color_grey;
}
- input:not(.form-control), textarea {
- background-color: @alertify-input-fg;
- color: @cryptpad_text_col;
- border: 1px solid @alertify-input-bg;
- margin-bottom: @alertify_padding-base;
- width: 100%;
- font-size: 100%;
- padding: @alertify_padding-base;
- &[readonly] {
- background-color: @alertify-light-bg;
- color: @cryptpad_text_col;
- border-color: @alertify-light-bg;
- }
- }
-
- textarea {
- overflow: hidden;
- padding: 8px;
- &[readonly] {
- resize: none;
- }
- }
span.cp-password-container {
display: flex;
@@ -271,99 +250,17 @@
}
}
- button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button) {
+ .buttons_main();
+ input:not(.form-control), textarea {
+ margin-bottom: 15px;
+ }
- background-color: @colortheme_alertify-cancel;
- box-sizing: border-box;
- position: relative;
- outline: 0;
+ button {
display: inline-block;
- align-items: center;
- padding: 0 6px;
+ position: relative;
margin: 6px 8px;
- line-height: 36px;
min-height: 36px;
- white-space: nowrap;
min-width: 88px;
- text-align: center;
- text-transform: uppercase;
- font-size: 14px;
- text-decoration: none;
- cursor: pointer;
- border-radius: 0;
-
- color: @alertify-btn-fg;
- border: 1px solid @alertify-btn-fg;
-
- &.no-margin {
- margin: 0;
- }
-
- &:hover, &:active {
- background-color: @alertify-light-bg;
- }
-
- &.safe, &.danger {
- color: @colortheme_old-base;
- white-space: normal;
- font-weight: bold;
- }
- &.danger {
- background-color: @colortheme_alertify-red;
- border-color: @colortheme_alertify-red-border;
- color: @colortheme_alertify-red-color;
- &:hover, &:active {
- background-color: contrast(@colortheme_modal-bg, darken(@colortheme_alertify-red, 10%), lighten(@colortheme_alertify-red, 10%));
- }
- }
-
- &.safe {
- background-color: @colortheme_alertify-green;
- border-color: @colortheme_alertify-green-border;
- color: @colortheme_alertify-green-color;
- &:hover, &:active {
- background-color: contrast(@colortheme_modal-bg, darken(@colortheme_alertify-green, 10%), lighten(@colortheme_alertify-green, 10%));
- }
- }
-
- &.primary {
- background-color: @colortheme_alertify-primary;
- color: @colortheme_alertify-primary-text;
- border-color: @colortheme_alertify-primary-border;
- font-weight: bold;
- &:hover, &:active {
- background-color: contrast(@colortheme_modal-bg, darken(@colortheme_alertify-primary, 10%), lighten(@colortheme_alertify-primary, 10%));
- }
- }
-
- &.cancel {
- border-color: @colortheme_alertify-cancel-border;
- color: @colortheme_alertify-cancel-border;
- &:hover, &:hover {
- background-color: fade(@colortheme_alertify-cancel-border, 25%);
- }
- }
-
-
-
- &:focus {
- //border: 1px dotted @alertify-base;
- box-shadow: 0px 0px 5px @colortheme_alertify-primary;
- outline: none;
- }
- &::-moz-focus-inner {
- border: 0;
- }
-
- &:disabled {
- cursor: not-allowed !important;
- background-color: @colortheme_alertify-disabled;
- color: @colortheme_alertify-disabled-text;
- border-color: @colortheme_alertify-disabled-border;
- &:hover, &:active {
- background-color: @colortheme_alertify-disabled;
- }
- }
}
nav {
diff --git a/customize.dist/src/less2/include/buttons.less b/customize.dist/src/less2/include/buttons.less
new file mode 100644
index 000000000..f3cb50e17
--- /dev/null
+++ b/customize.dist/src/less2/include/buttons.less
@@ -0,0 +1,129 @@
+@import (reference) "./colortheme-all.less";
+@import (reference) "./variables.less";
+
+.buttons_main() {
+ @alertify-fore: @colortheme_modal-fg;
+ @alertify-btn-fg: @alertify-fore;
+ @alertify-light-bg: fade(@alertify-fore, 25%);
+ @alertify_padding-base: @variables_padding;
+ @alertify-input-bg: @colortheme_modal-input;
+ @alertify-input-fg: @colortheme_modal-input-fg;
+
+ input:not(.form-control), textarea {
+ background-color: @alertify-input-fg;
+ color: @cryptpad_text_col;
+ border: 1px solid @alertify-input-bg;
+ width: 100%;
+ font-size: 100%;
+ padding: @alertify_padding-base;
+ &[readonly] {
+ background-color: @alertify-light-bg;
+ color: @cryptpad_text_col;
+ border-color: @alertify-input-fg;
+ }
+ }
+
+ textarea {
+ overflow: hidden;
+ padding: 8px;
+ &[readonly] {
+ resize: none;
+ }
+ }
+
+
+ button:not(.pure-button):not(.md-button):not(.mdl-button) {
+
+ background-color: @colortheme_alertify-cancel;
+ box-sizing: border-box;
+ outline: 0;
+ align-items: center;
+ padding: 0 6px;
+ line-height: 36px;
+ white-space: nowrap;
+ text-align: center;
+ text-transform: uppercase;
+ font-size: 14px;
+ text-decoration: none;
+ cursor: pointer;
+ border-radius: 0;
+
+ .fa {
+ margin-right: 0.2em;
+ }
+
+ color: @alertify-btn-fg;
+ border: 1px solid @alertify-btn-fg;
+
+ &.no-margin {
+ margin: 0;
+ }
+
+ &:hover, &:active {
+ background-color: lighten(@alertify-fore, 35%);
+ }
+
+ &.safe, &.danger, &.btn-safe, &.btn-danger {
+ color: @colortheme_old-base;
+ white-space: normal;
+ font-weight: bold;
+ }
+ &.danger, &.btn-danger {
+ background-color: @colortheme_alertify-red;
+ border-color: @colortheme_alertify-red-border;
+ color: @colortheme_alertify-red-color;
+ &:hover, &:active {
+ background-color: contrast(@colortheme_modal-bg, darken(@colortheme_alertify-red, 10%), lighten(@colortheme_alertify-red, 10%));
+ }
+ }
+
+ &.safe, &.btn-safe {
+ background-color: @colortheme_alertify-green;
+ border-color: @colortheme_alertify-green-border;
+ color: @colortheme_alertify-green-color;
+ &:hover, &:active {
+ background-color: contrast(@colortheme_modal-bg, darken(@colortheme_alertify-green, 10%), lighten(@colortheme_alertify-green, 10%));
+ }
+ }
+
+ &.primary, &.btn-primary {
+ background-color: @colortheme_alertify-primary;
+ color: @colortheme_alertify-primary-text;
+ border-color: @colortheme_alertify-primary-border;
+ font-weight: bold;
+ &:hover, &:active {
+ background-color: contrast(@colortheme_modal-bg, darken(@colortheme_alertify-primary, 10%), lighten(@colortheme_alertify-primary, 10%));
+ }
+ }
+
+ &.cancel, &.btn-cancel {
+ border-color: @colortheme_alertify-cancel-border;
+ color: @colortheme_alertify-cancel-border;
+ &:hover, &:hover {
+ background-color: fade(@colortheme_alertify-cancel-border, 25%);
+ }
+ }
+
+
+
+ &:focus {
+ //border: 1px dotted @alertify-base;
+ box-shadow: 0px 0px 5px @colortheme_alertify-primary;
+ outline: none;
+ }
+ &::-moz-focus-inner {
+ border: 0;
+ }
+
+ &:disabled {
+ cursor: not-allowed !important;
+ background-color: @colortheme_alertify-disabled;
+ color: @colortheme_alertify-disabled-text;
+ border-color: @colortheme_alertify-disabled-border;
+ &:hover, &:active {
+ background-color: @colortheme_alertify-disabled;
+ }
+ }
+ }
+
+}
diff --git a/customize.dist/src/less2/include/mediatag.less b/customize.dist/src/less2/include/mediatag.less
index 704fd71bd..f8255aab3 100644
--- a/customize.dist/src/less2/include/mediatag.less
+++ b/customize.dist/src/less2/include/mediatag.less
@@ -7,6 +7,13 @@
text-align: center;
}
+ media-tag:empty {
+ width: 100px;
+ height: 100px;
+ display: inline-block;
+ border: 1px solid #BBB;
+ }
+
media-tag img {
flex: 1;
max-height: 100% !important;
diff --git a/customize.dist/src/less2/include/messenger.less b/customize.dist/src/less2/include/messenger.less
index 0215cd4bc..ddf1540c9 100644
--- a/customize.dist/src/less2/include/messenger.less
+++ b/customize.dist/src/less2/include/messenger.less
@@ -78,6 +78,9 @@
.cp-app-contacts-name {
white-space: nowrap;
}
+ .cp-app-contacts-icons {
+ text-align: right;
+ }
}
&:hover {
background-color: rgba(0,0,0,0.3);
@@ -89,6 +92,7 @@
.cp-app-contacts-remove {
cursor: pointer;
width: 20px;
+ text-align: center;
&:hover {
color: darken(@color, 20%);
}
@@ -121,6 +125,15 @@
}
}
}
+ .cp-app-contacts-muted-button {
+ margin: 10px;
+ border: 0;
+ display: none;
+ order: 3;
+ .fa-bell-slash {
+ margin-right: 10px;
+ }
+ }
}
}
diff --git a/customize.dist/src/less2/include/modals-ui-elements.less b/customize.dist/src/less2/include/modals-ui-elements.less
index 21707eab8..665345ad6 100644
--- a/customize.dist/src/less2/include/modals-ui-elements.less
+++ b/customize.dist/src/less2/include/modals-ui-elements.less
@@ -28,4 +28,14 @@
.cp-app-prop-content {
color: @cryptpad_text_col;
}
+
+ .cp-contacts-muted-user {
+ margin-bottom: 5px;
+ .cp-avatar {
+ margin-right: 10px;
+ }
+ .button {
+ margin-right: 0px; // XXX
+ }
+ }
}
diff --git a/customize.dist/src/less2/include/sidebar-layout.less b/customize.dist/src/less2/include/sidebar-layout.less
index 24228cfaf..42de195d0 100644
--- a/customize.dist/src/less2/include/sidebar-layout.less
+++ b/customize.dist/src/less2/include/sidebar-layout.less
@@ -1,5 +1,6 @@
@import (reference) "/customize/src/less2/include/colortheme-all.less";
@import (reference) "/customize/src/less2/include/leftside-menu.less";
+@import (reference) "/customize/src/less2/include/buttons.less";
@sidebar_button-width: 400px;
@@ -98,6 +99,7 @@
}
[type="text"], [type="password"], button {
vertical-align: middle;
+ min-width: 40px;
height: 40px;
box-sizing: border-box;
}
@@ -106,12 +108,12 @@
width: @sidebar_button-width;
input {
flex: 1;
- border-radius: 0.25em 0 0 0.25em;
+ //border-radius: 0.25em 0 0 0.25em;
border: 1px solid #adadad;
border-right: 0px;
}
button {
- border-radius: 0 0.25em 0.25em 0;
+ //border-radius: 0 0.25em 0.25em 0;
//border: 1px solid #adadad;
border-left: 0px;
}
@@ -119,6 +121,14 @@
&>div {
margin: 10px 0;
}
+ .buttons_main();
+ button.btn {
+ margin: 0 5px 0 0;
+ }
+ span.cp-password-container {
+ margin-bottom: 1px;
+ }
+/*
button.btn {
@button-bg: @colortheme_sidebar-button-bg;
@button-red-bg: @colortheme_sidebar-button-red-bg;
@@ -126,6 +136,9 @@
background-color: @button-bg;
border-color: darken(@button-bg, 10%);
color: white;
+ .fa {
+ margin-right: 0.2em;
+ }
&:hover {
background-color: darken(@button-bg, 10%);
}
@@ -146,6 +159,7 @@
}
}
}
+*/
}
}
}
diff --git a/www/code/app-code.less b/www/code/app-code.less
index f07ef534d..219143a34 100644
--- a/www/code/app-code.less
+++ b/www/code/app-code.less
@@ -98,6 +98,13 @@
max-height: 90vh;
}
}
+ media-tag:empty {
+ width: 100px;
+ height: 100px;
+ display: inline-block;
+ border: 1px solid #BBB;
+ }
+
.markdown_main();
.cp-app-code-preview-empty {
display: none;
diff --git a/www/common/common-interface.js b/www/common/common-interface.js
index 4c78d2488..4528b7a1b 100644
--- a/www/common/common-interface.js
+++ b/www/common/common-interface.js
@@ -592,6 +592,7 @@ define([
}];
var modal = dialog.customModal(content, {buttons: buttons});
UI.openCustomModal(modal);
+ return modal;
};
UI.log = function (msg) {
diff --git a/www/common/common-messaging.js b/www/common/common-messaging.js
index 91322f526..feb3d79d3 100644
--- a/www/common/common-messaging.js
+++ b/www/common/common-messaging.js
@@ -84,6 +84,7 @@ define([
var myData = createData(store.proxy, false);
if (store.proxy.friends) {
store.proxy.friends.me = myData;
+ delete store.proxy.friends.me.channel;
}
if (store.modules['team']) {
store.modules['team'].updateMyData(myData);
diff --git a/www/common/common-ui-elements.js b/www/common/common-ui-elements.js
index d9610c822..64ae9dd0d 100644
--- a/www/common/common-ui-elements.js
+++ b/www/common/common-ui-elements.js
@@ -3977,7 +3977,7 @@ define([
};
var content = h('div.cp-share-modal', [
- setHTML(h('p'), text)
+ setHTML(h('p'), text),
]);
UI.proposal(content, todo);
};
diff --git a/www/common/media-tag.js b/www/common/media-tag.js
index a2beb3b4a..27683c54e 100644
--- a/www/common/media-tag.js
+++ b/www/common/media-tag.js
@@ -435,8 +435,6 @@
return mediaObject;
}
- mediaObject.tag.innerHTML = '
';
-
// Download the encrypted blob
download(src, function (err, u8Encrypted) {
if (err) {
diff --git a/www/common/messenger-ui.js b/www/common/messenger-ui.js
index 1979bae66..a132dcf00 100644
--- a/www/common/messenger-ui.js
+++ b/www/common/messenger-ui.js
@@ -3,9 +3,10 @@ define([
'/customize/messages.js',
'/common/common-util.js',
'/common/common-interface.js',
+ '/common/common-ui-elements.js',
'/common/hyperscript.js',
'/common/diffMarked.js',
-], function ($, Messages, Util, UI, h, DiffMd) {
+], function ($, Messages, Util, UI, UIElements, h, DiffMd) {
'use strict';
var debug = console.log;
@@ -13,6 +14,8 @@ define([
var MessengerUI = {};
+ var mutedUsers = {};
+
var dataQuery = function (id) {
return '[data-key="' + id + '"]';
};
@@ -67,8 +70,11 @@ define([
h('div.cp-app-contacts-category-content')
]),
h('div.cp-app-contacts-friends.cp-app-contacts-category', [
- h('div.cp-app-contacts-category-content'),
- h('h2.cp-app-contacts-category-title', Messages.contacts_friends),
+ h('button.cp-app-contacts-muted-button',[
+ h('i.fa.fa-bell-slash'),
+ Messages.contacts_manageMuted || 'MANAGE MUTED' // XXX
+ ]),
+ h('div.cp-app-contacts-category-content.cp-contacts-friends')
]),
h('div.cp-app-contacts-rooms.cp-app-contacts-category', [
h('div.cp-app-contacts-category-content'),
@@ -184,7 +190,7 @@ define([
markup.message = function (msg) {
if (msg.type !== 'MSG') { return; }
var curvePublic = msg.author;
- var name = typeof msg.name !== "undefined" ?
+ var name = (typeof msg.name !== "undefined" || !contactsData[msg.author]) ?
(msg.name || Messages.anonymous) :
contactsData[msg.author].displayName;
var d = msg.time ? new Date(msg.time) : undefined;
@@ -486,6 +492,20 @@ define([
}
};
+ var unmuteUser = function (curve) {
+ execCommand('UNMUTE_USER', curve, function (e) {
+ if (e) { return void console.error(e); }
+ });
+ };
+ var muteUser = function (data) {
+ execCommand('MUTE_USER', {
+ curvePublic: data.curvePublic,
+ name: data.displayName || data.name,
+ avatar: data.avatar
+ }, function (e /*, removed */) {
+ if (e) { return void console.error(e); }
+ });
+ };
var removeFriend = function (curvePublic) {
execCommand('REMOVE_FRIEND', curvePublic, function (e /*, removed */) {
if (e) { return void console.error(e); }
@@ -499,6 +519,21 @@ define([
title: room.name
});
+
+ var curve;
+ if (room.isFriendChat) {
+ var __channel = state.channels[id];
+ curve = __channel.curvePublic;
+ }
+
+ var unmute = h('span.cp-app-contacts-remove.fa.fa-bell.cp-unmute-icon', {
+ title: Messages.contacts_unmute || 'unmute',
+ style: (curve && mutedUsers[curve]) ? undefined : 'display: none;'
+ });
+ var mute = h('span.cp-app-contacts-remove.fa.fa-bell-slash.cp-mute-icon', {
+ title: Messages.contacts_mute || 'mute',
+ style: (curve && mutedUsers[curve]) ? 'display: none;' : undefined
+ });
var remove = h('span.cp-app-contacts-remove.fa.fa-user-times', {
title: Messages.contacts_remove
});
@@ -511,8 +546,12 @@ define([
});
var rightCol = h('span.cp-app-contacts-right-col', [
h('span.cp-app-contacts-name', [room.name]),
- room.isFriendChat ? remove :
- (room.isPadChat || room.isTeamChat) ? undefined : leaveRoom,
+ h('span.cp-app-contacts-icons', [
+ room.isFriendChat ? mute : undefined,
+ room.isFriendChat ? unmute : undefined,
+ room.isFriendChat ? remove :
+ (room.isPadChat || room.isTeamChat) ? undefined : leaveRoom,
+ ])
]);
var friendData = room.isFriendChat ? userlist[0] : {};
@@ -523,23 +562,43 @@ define([
if (friendData.profile) { window.open(origin + '/profile/#' + friendData.profile); }
});
+ $(unmute).on('click dblclick', function (e) {
+ e.stopPropagation();
+ var channel = state.channels[id];
+ if (!channel.isFriendChat) { return; }
+ var curvePublic = channel.curvePublic;
+ $(mute).show();
+ $(unmute).hide();
+ unmuteUser(curvePublic);
+ });
+
+ $(mute).on('click dblclick', function (e) {
+ e.stopPropagation();
+ var channel = state.channels[id];
+ if (!channel.isFriendChat) { return; }
+ var curvePublic = channel.curvePublic;
+ var friend = contactsData[curvePublic] || friendData;
+ $(mute).hide();
+ $(unmute).show();
+ muteUser(friend);
+ });
+
$(remove).click(function (e) {
e.stopPropagation();
var channel = state.channels[id];
if (!channel.isFriendChat) { return; }
var curvePublic = channel.curvePublic;
var friend = contactsData[curvePublic] || friendData;
- UI.confirm(Messages._getKey('contacts_confirmRemove', [
- Util.fixHTML(friend.name)
- ]), function (yes) {
+ var content = h('div', [
+ UI.setHTML(h('p'), Messages._getKey('contacts_confirmRemove', [Util.fixHTML(friend.name)])),
+ ]);
+ UI.confirm(content, function (yes) {
if (!yes) { return; }
- removeFriend(curvePublic, function (e) {
- if (e) { return void console.error(e); }
- });
+ removeFriend(curvePublic);
// TODO remove friend from userlist ui
// FIXME seems to trigger EJOINED from netflux-websocket (from server);
// (tried to join a channel in which you were already present)
- }, undefined, true);
+ });
});
if (friendData.avatar && avatars[friendData.avatar]) {
@@ -792,6 +851,62 @@ define([
// var onJoinRoom
// var onLeaveRoom
+ var updateMutedList = function () {
+ execCommand('GET_MUTED_USERS', null, function (err, muted) {
+ if (err) { return void console.error(err); }
+ mutedUsers = muted;
+
+ var $button = $userlist.find('.cp-app-contacts-muted-button');
+
+ $('.cp-app-contacts-friend[data-user]')
+ .find('.cp-mute-icon').show();
+ $('.cp-app-contacts-friend[data-user]')
+ .find('.cp-unmute-icon').hide();
+ if (!muted || Object.keys(muted).length === 0) {
+ $button.hide();
+ return;
+ }
+
+ var rows = Object.keys(muted).map(function (curve) {
+ $('.cp-app-contacts-friend[data-user="'+curve+'"]')
+ .find('.cp-mute-icon').hide();
+ $('.cp-app-contacts-friend[data-user="'+curve+'"]')
+ .find('.cp-unmute-icon').show();
+ var data = muted[curve];
+ var avatar = h('span.cp-avatar');
+ var button = h('button', {
+ 'data-user': curve
+ }, [
+ h('i.fa.fa-bell'),
+ Messages.contacts_unmute || 'unmute'
+ ]);
+ UIElements.displayAvatar(common, $(avatar), data.avatar, data.name);
+ $(button).click(function () {
+ unmuteUser(curve, button);
+ execCommand('UNMUTE_USER', curve, function (e, data) {
+ if (e) { return void console.error(e); }
+ $(button).closest('div').remove();
+ if (!data) { $button.hide(); }
+ $('.cp-app-contacts-friend[data-user="'+curve+'"]')
+ .find('.cp-mute-icon').show();
+ });
+ });
+ return h('div.cp-contacts-muted-user', [
+ h('span', avatar),
+ h('span', data.name),
+ button
+ ]);
+ });
+ var content = h('div', [
+ h('h4', Messages.contacts_mutedUsers || 'Muted users...'),
+ h('div.cp-contacts-muted-table', rows)
+ ]);
+ $button.off('click');
+ $button.click(function () {
+ UI.alert(content);
+ }).show();
+ });
+ };
var ready = false;
var onMessengerReady = function () {
@@ -806,6 +921,8 @@ define([
rooms.forEach(initializeRoom);
});
+ updateMutedList();
+
$container.removeClass('cp-app-contacts-initializing');
};
@@ -882,6 +999,10 @@ define([
onUpdateData(data);
return;
}
+ if (cmd === 'UPDATE_MUTED') {
+ updateMutedList();
+ return;
+ }
if (cmd === 'MESSAGE') {
onMessage(data);
return;
diff --git a/www/common/outer/mailbox-handlers.js b/www/common/outer/mailbox-handlers.js
index 00f990eb3..6e10cd5a2 100644
--- a/www/common/outer/mailbox-handlers.js
+++ b/www/common/outer/mailbox-handlers.js
@@ -12,6 +12,13 @@ define([
var handlers = {};
var removeHandlers = {};
+ var isMuted = function (ctx, data) {
+ var muted = ctx.store.proxy.mutedUsers || {};
+ var curvePublic = Util.find(data, ['msg', 'author']);
+ if (!curvePublic) { return false; }
+ return Boolean(muted[curvePublic]);
+ };
+
// Store the friend request displayed to avoid duplicates
var friendRequest = {};
handlers['FRIEND_REQUEST'] = function (ctx, box, data, cb) {
@@ -21,6 +28,8 @@ define([
return void cb(true);
}
+ if (isMuted(ctx, data)) { return void cb(true); }
+
// Don't show duplicate friend request: if we already have a friend request
// in memory from the same user, dismiss the new one
if (friendRequest[data.msg.author]) { return void cb(true); }
@@ -30,10 +39,22 @@ define([
// If the user is already in our friend list, automatically accept the request
if (Messaging.getFriend(ctx.store.proxy, data.msg.author) ||
ctx.store.proxy.friends_pending[data.msg.author]) {
+ delete ctx.store.proxy.friends_pending[data.msg.author];
Messaging.acceptFriendRequest(ctx.store, data.msg.content, function (obj) {
if (obj && obj.error) {
return void cb();
}
+ Messaging.addToFriendList({
+ proxy: ctx.store.proxy,
+ realtime: ctx.store.realtime,
+ pinPads: ctx.pinPads
+ }, data.msg.content, function (err) {
+ if (err) { console.error(err); }
+ if (ctx.store.messenger) {
+ ctx.store.messenger.onFriendAdded(data.msg.content);
+ }
+ });
+ ctx.updateMetadata();
cb(true);
});
return;
@@ -170,6 +191,8 @@ define([
var content = msg.content;
// content.name, content.title, content.href, content.password
+ if (isMuted(ctx, data)) { return void cb(true); }
+
var channel = Hash.hrefToHexChannelId(content.href, content.password);
var parsed = Hash.parsePadUrl(content.href);
var mode = parsed.hashData && parsed.hashData.mode || 'n/a';
@@ -212,6 +235,9 @@ define([
supportMessage = true;
cb();
};
+ removeHandlers['SUPPORT_MESSAGE'] = function () {
+ supportMessage = false;
+ };
// Incoming edit rights request: add data before sending it to inner
handlers['REQUEST_PAD_ACCESS'] = function (ctx, box, data, cb) {
@@ -220,6 +246,8 @@ define([
if (msg.author !== content.user.curvePublic) { return void cb(true); }
+ if (isMuted(ctx, data)) { return void cb(true); }
+
var channel = content.channel;
var res = ctx.store.manager.findChannel(channel);
@@ -270,6 +298,9 @@ define([
var content = msg.content;
if (msg.author !== content.user.curvePublic) { return void cb(true); }
+
+ if (isMuted(ctx, data)) { return void cb(true); }
+
if (!content.teamChannel && !(content.href && content.title && content.channel)) {
console.log('Remove invalid notification');
return void cb(true);
@@ -327,6 +358,9 @@ define([
var content = msg.content;
if (msg.author !== content.user.curvePublic) { return void cb(true); }
+
+ if (isMuted(ctx, data)) { return void cb(true); }
+
if (!content.team) {
console.log('Remove invalid notification');
return void cb(true);
diff --git a/www/common/outer/messenger.js b/www/common/outer/messenger.js
index d0e200deb..4d5e42973 100644
--- a/www/common/outer/messenger.js
+++ b/www/common/outer/messenger.js
@@ -428,20 +428,21 @@ define([
}
var channel = ctx.channels[data.channel];
- if (!channel) {
- return void cb({error: "NO_SUCH_CHANNEL"});
- }
// Unfriend with mailbox
if (ctx.store.mailbox && data.curvePublic && data.notifications) {
Messaging.removeFriend(ctx.store, curvePublic, function (obj) {
if (obj && obj.error) { return void cb({error:obj.error}); }
+ ctx.updateMetadata();
cb(obj);
});
return;
}
// Unfriend with channel
+ if (!channel) {
+ return void cb({error: "NO_SUCH_CHANNEL"});
+ }
try {
var msg = [Types.unfriend, proxy.curvePublic, +new Date()];
var msgStr = JSON.stringify(msg);
@@ -458,6 +459,40 @@ define([
}
};
+ var getAllClients = function (ctx) {
+ var all = [];
+ Array.prototype.push.apply(all, ctx.friendsClients);
+ Object.keys(ctx.channels).forEach(function (id) {
+ Array.prototype.push.apply(all, ctx.channels[id].clients);
+ });
+ return Util.deduplicateString(all);
+ };
+
+ var muteUser = function (ctx, data, _cb) {
+ var cb = Util.once(Util.mkAsync(_cb));
+ var proxy = ctx.store.proxy;
+ var muted = proxy.mutedUsers = proxy.mutedUsers || {};
+ if (muted[data.curvePublic]) { return void cb(); }
+ muted[data.curvePublic] = data;
+ ctx.emit('UPDATE_MUTED', null, getAllClients(ctx));
+ cb();
+ };
+ var unmuteUser = function (ctx, curvePublic, _cb) {
+ var cb = Util.once(Util.mkAsync(_cb));
+ var proxy = ctx.store.proxy;
+ var muted = proxy.mutedUsers = proxy.mutedUsers || {};
+ delete muted[curvePublic];
+ ctx.emit('UPDATE_MUTED', null, getAllClients(ctx));
+ cb(Object.keys(muted).length);
+ };
+ var getMutedUsers = function (ctx, cb) {
+ var proxy = ctx.store.proxy;
+ if (cb) {
+ return void cb(proxy.mutedUsers || {});
+ }
+ return proxy.mutedUsers || {};
+ };
+
var openChannel = function (ctx, data) {
var proxy = ctx.store.proxy;
var network = ctx.store.network;
@@ -664,7 +699,14 @@ define([
nThen(function (waitFor) {
// Load or get all friends channels
Object.keys(friends).forEach(function (key) {
- if (key === 'me') { return; }
+ if (key === 'me') {
+ // At some point a bug inserted a friend's channel into our "me" data.
+ // This led to displaying our name instead of our friend's name in the
+ // contacts app. The following line is here to prevent this issue to happen
+ // again.
+ delete friends.me.channel;
+ return;
+ }
var friend = clone(friends[key]);
if (typeof(friend) !== 'object') { return; }
if (!friend.channel) { return; }
@@ -887,15 +929,6 @@ define([
});
};
- var getAllClients = function (ctx) {
- var all = [];
- Array.prototype.push.apply(all, ctx.friendsClients);
- Object.keys(ctx.channels).forEach(function (id) {
- Array.prototype.push.apply(all, ctx.channels[id].clients);
- });
- return Util.deduplicateString(all);
- };
-
Msg.init = function (cfg, waitFor, emit) {
var messenger = {};
var store = cfg.store;
@@ -911,6 +944,9 @@ define([
range_requests: {}
};
+ store.proxy.on('change', ['mutedUsers'], function () {
+ ctx.emit('UPDATE_MUTED', null, getAllClients(ctx));
+ });
ctx.store.network.on('message', function(msg, sender) {
onDirectMessage(ctx, msg, sender);
@@ -942,6 +978,12 @@ define([
var channel = friend.channel;
if (!channel) { return; }
+ // Already friend? don't load the channel a second time
+ var chanId = friend.channel;
+ var chan = ctx.channels[chanId];
+ if (chan) { return; }
+
+ // Load the channel and add the friend to the contacts app
loadFriend(ctx, null, friend, function () {
emit('FRIEND', {
curvePublic: friend.curvePublic,
@@ -990,6 +1032,9 @@ define([
if (cmd === 'GET_ROOMS') {
return void getRooms(ctx, data, cb);
}
+ if (cmd === 'GET_MUTED_USERS') {
+ return void getMutedUsers(ctx, cb);
+ }
if (cmd === 'GET_USERLIST') {
return void getUserList(ctx, data, cb);
}
@@ -1002,6 +1047,12 @@ define([
if (cmd === 'REMOVE_FRIEND') {
return void removeFriend(ctx, data, cb);
}
+ if (cmd === 'MUTE_USER') {
+ return void muteUser(ctx, data, cb);
+ }
+ if (cmd === 'UNMUTE_USER') {
+ return void unmuteUser(ctx, data, cb);
+ }
if (cmd === 'GET_STATUS') {
return void getStatus(ctx, data, cb);
}
diff --git a/www/contacts/app-contacts.less b/www/contacts/app-contacts.less
index 32753f136..88a93ae9d 100644
--- a/www/contacts/app-contacts.less
+++ b/www/contacts/app-contacts.less
@@ -1,5 +1,7 @@
@import (reference) '../../customize/src/less2/include/framework.less';
@import (reference) '../../customize/src/less2/include/messenger.less';
+@import (reference) '../../customize/src/less2/include/avatar.less';
+@import (reference) '../../customize/src/less2/include/buttons.less';
// body
&.cp-app-contacts {
@@ -17,6 +19,22 @@
display: flex; // We need this to remove a 3px border at the bottom of the toolbar
}
+ .cp-app-contacts-friends {
+ .buttons_main();
+ }
+ .cp-contacts-muted-table {
+ .avatar_main(50px);
+ .cp-contacts-muted-user {
+ display: flex;
+ align-items: center;
+ span:nth-child(2) {
+ flex: 1;
+ }
+ }
+ }
+
+
+
.messenger_main();
}
diff --git a/www/profile/app-profile.less b/www/profile/app-profile.less
index 1284f31c4..9ec06de18 100644
--- a/www/profile/app-profile.less
+++ b/www/profile/app-profile.less
@@ -10,8 +10,15 @@
);
.sidebar-layout_main();
+ @cp-profile-is-your-friend: #777;
+
display: flex;
flex-flow: column;
+
+ #cp-sidebarlayout-leftside {
+ display: none !important;
+ }
+
#cp-app-profile-header {
display: flex;
#cp-app-profile-rightside {
@@ -64,8 +71,9 @@
}
}
button {
+ min-width: 40px;
height: 40px;
- margin: 5px;
+ margin: 5px !important;
}
}
.cp-app-profile-resizer {
@@ -108,10 +116,18 @@
display: none;
}
& > button:empty {
- margin-left: 25px;
+ margin-left: 25px !important;
}
}
+ .cp-app-profile-friend {
+ display: flex;
+ align-items: center;
+ color: @cp-profile-is-your-friend;
+ .fa {
+ margin-right: 0.2em;
+ }
+ }
.cp-app-profile-friend-request {
flex: 0;
width: 400px;
@@ -126,9 +142,6 @@
margin-bottom: 20px;
float: right;
margin-left: 5px;
- &> span {
- margin-left: 10px;
- }
}
#cp-app-profile-description {
position: relative;
@@ -166,13 +179,6 @@
line-height: inherit;
}
}
- .cp-app-profile-description-edit {
- & > button {
- span {
- margin-left: 10px;
- }
- }
- }
}
#cp-app-profile-create {
height: 100%;
@@ -181,5 +187,12 @@
align-items: center;
justify-content: center;
}
+ .cp-app-profile-mute-container {
+ margin-top: 5px;
+ p {
+ margin-top: 5px;
+ font-size: 13px;
+ }
+ }
}
diff --git a/www/profile/inner.js b/www/profile/inner.js
index 054144342..e9c142777 100644
--- a/www/profile/inner.js
+++ b/www/profile/inner.js
@@ -178,9 +178,6 @@ define([
var addFriendRequest = function ($container) {
if (!APP.readOnly || !APP.common.isLoggedIn()) { return; }
- APP.$friend = $('