Added editing own nickname.

Fix dark theme support.
Fix notification titles.
pull/61/head
Mikunj 6 years ago
parent 449f44cc5a
commit 98c4b5d77b

@ -63,9 +63,7 @@
</div>
</div>
</div>
<div class='identityKeyWrapper'>
Your identity key: <span class='identityKey'>{{ identityKey }}</span>
</div>
<div class='identity-key-placeholder'></div>
<div class='underneathIdentityWrapper'>
<div class='conversation-stack'>
<div class='conversation placeholder'>
@ -155,8 +153,10 @@
{{ #title }}
<h4>{{ title }}</h4>
{{ /title }}
<div class='message'>{{ message }}</div>
<input type='text' name='name' class='name' placeholder='Type a nickname' value='{{ name }}'>
<input type='text' name='name' class='name' placeholder='Type a nickname' autofocus maxlength="25">
{{ #message }}
<div class='message'>{{ message }}</div>
{{ /message }}
<div class='buttons'>
<button class='clear' tabindex='3'>{{ clear }}</button>
<button class='cancel' tabindex='2'>{{ cancel }}</button>

@ -568,6 +568,40 @@
}
});
Whisper.events.on('onEditProfile', () => {
const ourNumber = textsecure.storage.user.getNumber();
const profile = storage.getProfile(ourNumber);
const nickname = profile && profile.name && profile.name.displayName;
if (appView) {
appView.showNicknameDialog({
title: 'Change your own nickname',
message: 'Note: Your nickname will be visible to your contacts.',
nickname,
onOk: async (newNickname) => {
// Update our profiles accordingly
if (_.isEmpty(newNickname)) {
await storage.removeProfile(ourNumber);
} else {
await storage.saveProfile(ourNumber, {
name: {
displayName: newNickname,
},
});
}
appView.inboxView.trigger('updateProfile');
// Update the conversation if we have it
try {
const conversation = ConversationController.get(ourNumber);
conversation.updateProfile();
} catch (e) {}
},
})
}
});
Whisper.events.on('showNicknameDialog', options => {
if (appView) {
appView.showNicknameDialog(options);

@ -1736,7 +1736,15 @@
this.getProfiles();
}
},
// Update profile variables dynamically
/*
Update profile values from the profile in storage.
Signal has methods of setting data from a profile it fetches.
It fetches this via a server and they aren't saved anywhere.
We made our own profile storage system so thus to avoid
any future conflict with upstream, we just use this method to update the values.
*/
async updateProfile() {
const profileName = this.get('profileName');
@ -2083,7 +2091,10 @@
getTitle() {
if (this.isPrivate()) {
return this.get('name') || this.getNumber();
const profileName = this.getProfileName();
const number = this.getNumber();
const name = profileName ? `${profileName} (${number})` : number;
return this.get('name') || name;
}
return this.get('name') || 'Unknown group';
},

@ -43,6 +43,7 @@ const {
MediaGallery,
} = require('../../ts/components/conversation/media-gallery/MediaGallery');
const { MainHeader } = require('../../ts/components/MainHeader');
const { IdentityKeyHeader } = require('../../ts/components/IdentityKeyHeader');
const { Message } = require('../../ts/components/conversation/Message');
const { MessageBody } = require('../../ts/components/conversation/MessageBody');
const {
@ -184,6 +185,7 @@ exports.setup = (options = {}) => {
Lightbox,
LightboxGallery,
MainHeader,
IdentityKeyHeader,
MediaGallery,
Message,
MessageBody,

@ -178,10 +178,11 @@
});
}
},
showNicknameDialog({ pubKey, title, nickname, onOk, onCancel }) {
showNicknameDialog({ pubKey, title, message, nickname, onOk, onCancel }) {
const _title = title || `Change nickname for ${pubKey}`;
const dialog = new Whisper.NicknameDialogView({
title: _title,
message,
name: nickname,
resolve: onOk,
reject: onCancel,

@ -6,6 +6,7 @@
/* global textsecure: false */
/* global Signal: false */
/* global StringView: false */
/* global storage: false */
// eslint-disable-next-line func-names
(function() {
@ -42,7 +43,7 @@
if ($el && $el.length > 0) {
$el.remove();
}
}
},
});
Whisper.FontSizeView = Whisper.View.extend({
@ -113,6 +114,16 @@
this.listenTo(me, 'change', update);
this.$('.main-header-placeholder').append(this.mainHeaderView.el);
this.identityKeyView = new Whisper.ReactWrapperView({
className: 'identity-key-wrapper',
Component: Signal.Components.IdentityKeyHeader,
props: this._getIdentityKeyViewProps(),
});
this.on('updateProfile', () => {
this.identityKeyView.update(this._getIdentityKeyViewProps());
})
this.$('.identity-key-placeholder').append(this.identityKeyView.el);
this.conversation_stack = new Whisper.ConversationStack({
el: this.$('.conversation-stack'),
model: { window: options.window },
@ -184,14 +195,33 @@
this.$el.addClass('expired');
}
},
_getIdentityKeyViewProps() {
const identityKey = textsecure.storage.get('identityKey').pubKey;
const pubKey = StringView.arrayBufferToHex(identityKey);
const profile = storage.getProfile(pubKey);
const name = profile && profile.name && profile.name.displayName;
return {
identityKey: pubKey,
name,
onEditProfile: async () => {
window.Whisper.events.trigger('onEditProfile');
},
}
},
render_attributes() {
const identityKey = textsecure.storage.get('identityKey').pubKey;
const pubKey = StringView.arrayBufferToHex(identityKey);
const profile = storage.getProfile(pubKey);
const name = profile && profile.name && profile.name.displayName;
return {
welcomeToSignal: i18n('welcomeToSignal'),
selectAContact: i18n('selectAContact'),
searchForPeopleOrGroups: i18n('searchForPeopleOrGroups'),
settings: i18n('settings'),
identityKey: StringView.arrayBufferToHex(identityKey),
identityKey: pubKey,
name,
};
},
events: {

@ -27,6 +27,9 @@
this.render();
this.$input = this.$('input');
this.$input.val(this.name);
this.$input.focus();
this.validateNickname();
},
events: {
@ -36,9 +39,6 @@
'click .clear': 'clear',
change: 'validateNickname',
},
isValidNickname(name) {
return (name || '').length < 20;
},
validateNickname() {
const nickname = this.$input.val();
@ -47,19 +47,9 @@
} else {
this.$('.clear').show();
}
if (this.isValidNickname(nickname)) {
this.$('.content').removeClass('invalid');
this.$('.content').addClass('valid');
this.$('.ok').show();
} else {
this.$('.content').removeClass('valid');
this.$('.ok').hide();
}
},
render_attributes() {
return {
name: this.name,
message: this.message,
showCancel: !this.hideCancel,
cancel: this.cancelText,
@ -69,8 +59,7 @@
};
},
ok() {
const nickname = this.$input.val();
if (!this.isValidNickname(nickname)) return;
const nickname = this.$input.val().trim();
this.remove();
if (this.resolve) {
@ -87,12 +76,19 @@
this.$input.val('').trigger('change');
},
onKeyup(event) {
if (event.key === 'Escape' || event.key === 'Esc') {
this.cancel();
return;
}
this.validateNickname();
switch (event.key) {
case 'Enter':
this.ok();
break;
case 'Escape':
case 'Esc':
this.cancel();
break;
default:
return;
}
event.preventDefault();
},
focusCancel() {
this.$('.cancel').focus();

@ -351,7 +351,6 @@
}
}
.nickname-dialog {
display: flex;
align-items: center;
@ -359,6 +358,7 @@
.content {
max-width: 75%;
min-width: 60%;
padding: 1em;
background: white;
border-radius: $border-radius;
@ -399,6 +399,12 @@
word-wrap: break-word; /* IE */
word-break: break-all;
}
.message {
font-style: italic;
color: $grey;
font-size: 12px;
}
}
}

@ -71,21 +71,51 @@
}
}
.identityKeyWrapper {
.identity-key-wrapper {
background-color: $color-black-008-no-tranparency;
text-align: center;
height: 50px;
line-height: 50px;
display: flex;
flex: 1;
height: 60px;
padding-left: 16px;
padding-right: 16px;
}
.identity-key-container {
display: flex;
flex: 1;
flex-direction: row;
align-items: center;
justify-content: space-around;
white-space: nowrap;
overflow-x: hidden;
}
.identity-key-text-container {
flex: 1;
text-align: center;
flex-direction: column;
}
.identityKey {
.identity-key-container div {
overflow-x: hidden;
text-overflow: ellipsis;
}
.identity-key_bold {
font-weight: bold;
}
.identity-key-wrapper__pencil-icon {
@include color-svg('../images/lead-pencil.svg', $color-gray-60);
height: 20px;
width: 20px;
margin-left: 4px;
cursor: pointer;
}
.underneathIdentityWrapper {
position: absolute;
top: 50px;
top: 60px;
bottom: 0;
left: 300px;
right: 0;

@ -6,6 +6,16 @@ body.dark-theme {
}
.dark-theme {
// identity key
.identity-key-wrapper {
background-color:$color-gray-85;
}
.identity-key-wrapper__pencil-icon {
@include color-svg('../images/lead-pencil.svg', $color-gray-25);
}
// _conversation
.conversation {
@ -89,6 +99,37 @@ body.dark-theme {
}
}
.nickname-dialog {
.content {
background: $color-black;
color: $color-dark-05;
.buttons {
button {
background-color: $color-dark-85;
border-radius: $border-radius;
border: 1px solid $color-dark-60;
color: $color-dark-05;
&:hover {
background-color: $color-dark-70;
border-color: $color-dark-55;
}
}
}
input {
color: $color-dark-05;
background-color: $color-dark-70;
border-color: $color-dark-55;
}
.message {
color: $color-light-35;
}
}
}
.conversation-loading-screen {
background-color: $color-gray-95;
}

@ -0,0 +1,38 @@
import React from 'react';
interface Props {
identityKey: string;
name?: string;
onEditProfile: () => void;
}
export class IdentityKeyHeader extends React.Component<Props> {
public render() {
const {
name,
identityKey,
onEditProfile,
} = this.props;
return (
<div className='identity-key-container'>
<div className='identity-key-text-container'>
<div>
Your identity key: <span className='identity-key_bold'>{identityKey}</span>
</div>
{!!name &&
<div>
Your nickname: <span className='identity-key_bold'>{name}</span>
</div>
}
</div>
<div
id='editProfile'
role="button"
onClick={onEditProfile}
className="identity-key-wrapper__pencil-icon"
/>
</div>
);
}
}
Loading…
Cancel
Save