Merge pull request #69 from Mikunj/ui/header

Updated current profile display in UI
pull/72/head
sachaaaaa 7 years ago committed by GitHub
commit 4be6af569a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1656,5 +1656,18 @@
"editProfileDisplayNameWarning": { "editProfileDisplayNameWarning": {
"message": "Note: Your display name will be visible to your contacts", "message": "Note: Your display name will be visible to your contacts",
"description": "Shown to the user as a warning about setting display name" "description": "Shown to the user as a warning about setting display name"
},
"copyPublicKey": {
"message": "Copy public key",
"description": "Button action that the user can click to copy their public keys"
},
"copiedPublicKey": {
"message": "Copied public key",
"description": "A toast message telling the user that the key was copied"
},
"editDisplayName": {
"message": "Edit display name",
"description": "Button action that the user can click to edit their display name"
} }
} }

@ -49,7 +49,7 @@ const generateImage = pubKey => {
*/ */
const png = new Identicon(sha224(pubKey), { const png = new Identicon(sha224(pubKey), {
margin: 0.2, margin: 0.2,
background: [0,0,0,0], background: [0, 0, 0, 0],
}).toString(); }).toString();
fs.writeFileSync(imagePath, png, 'base64'); fs.writeFileSync(imagePath, png, 'base64');
return imagePath return imagePath

@ -71,7 +71,6 @@
<img src='images/loki/loki_icon_text.png'> <img src='images/loki/loki_icon_text.png'>
</div> </div>
</div> </div>
<div class='identity-key-placeholder'></div>
<div class='underneathIdentityWrapper'> <div class='underneathIdentityWrapper'>
<div class='conversation-stack'> <div class='conversation-stack'>
<div class='conversation placeholder'> <div class='conversation placeholder'>
@ -88,6 +87,16 @@
<div class='lightbox-container'></div> <div class='lightbox-container'></div>
</div> </div>
</script> </script>
<script type='text/x-tmpl-mustache' id='main-header-placeholder'>
<div class='main-header-title-wrapper'>
<div class='main-header-content-toggle'/>
</div>
<div class='main-header-content-wrapper'>
{{ #items }}
<div role='button' id='{{ id }}'>{{ text }}</div>
{{ /items }}
</div>
</script>
<script type='text/x-tmpl-mustache' id='scroll-down-button-view'> <script type='text/x-tmpl-mustache' id='scroll-down-button-view'>
<button class='text module-scroll-down__button {{ buttonClass }}' alt='{{ moreBelow }}'> <button class='text module-scroll-down__button {{ buttonClass }}' alt='{{ moreBelow }}'>
<div class='module-scroll-down__icon'></div> <div class='module-scroll-down__icon'></div>
@ -653,6 +662,7 @@
<script type='text/javascript' src='js/views/conversation_list_item_view.js'></script> <script type='text/javascript' src='js/views/conversation_list_item_view.js'></script>
<script type='text/javascript' src='js/views/conversation_list_view.js'></script> <script type='text/javascript' src='js/views/conversation_list_view.js'></script>
<script type='text/javascript' src='js/views/contact_list_view.js'></script> <script type='text/javascript' src='js/views/contact_list_view.js'></script>
<script type='text/javascript' src='js/views/main_header_view.js'></script>
<script type='text/javascript' src='js/views/new_group_update_view.js'></script> <script type='text/javascript' src='js/views/new_group_update_view.js'></script>
<script type='text/javascript' src='js/views/attachment_view.js'></script> <script type='text/javascript' src='js/views/attachment_view.js'></script>
<script type='text/javascript' src='js/views/timestamp_view.js'></script> <script type='text/javascript' src='js/views/timestamp_view.js'></script>

@ -580,7 +580,6 @@
nickname: displayName, nickname: displayName,
onOk: async (newName) => { onOk: async (newName) => {
await storage.setProfileName(newName); await storage.setProfileName(newName);
appView.inboxView.trigger('updateProfile');
// Update the conversation if we have it // Update the conversation if we have it
const conversation = ConversationController.get(ourNumber); const conversation = ConversationController.get(ourNumber);

@ -869,6 +869,11 @@
this.set({ id: this.id }); this.set({ id: this.id });
return 'Invalid ID Length'; return 'Invalid ID Length';
} }
// Check if the id is prefixed by 05
if (!/^05/.test(this.id)) {
return 'Invalid Pubkey Format';
}
} }
return null; return null;
@ -1616,12 +1621,12 @@
await this.updateProfile(); await this.updateProfile();
}, },
async setProfile(profile) { async setProfile(profile) {
if (_.isEqual(this.get('profile'), profile)) return; if (!_.isEqual(this.get('profile'), profile)) {
this.set({ profile });
this.set({ profile }); await window.Signal.Data.updateConversation(this.id, this.attributes, {
await window.Signal.Data.updateConversation(this.id, this.attributes, { Conversation: Whisper.Conversation,
Conversation: Whisper.Conversation, });
}); }
await this.updateProfile(); await this.updateProfile();
}, },

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

@ -73,7 +73,7 @@
// Update the contact model // Update the contact model
this.new_contact_view.model.set('id', query); this.new_contact_view.model.set('id', query);
this.new_contact_view.render().$el.show(); this.new_contact_view.render().$el.hide();
this.new_contact_view.validate(); this.new_contact_view.validate();
this.hideHints(); this.hideHints();
@ -89,10 +89,9 @@
// This will allow us to show the last message when searching // This will allow us to show the last message when searching
this.typeahead_view.collection.forEach(c => c.updateLastMessage()); this.typeahead_view.collection.forEach(c => c.updateLastMessage());
// Check if the query is in the model list // Show the new contact view if we already have results
// If it is then hide the new contact view if (this.typeahead_view.collection.length === 0)
const modelExists = this.typeahead_view.collection.find(item => item.get('id') === query); this.new_contact_view.$el.show();
if (modelExists) this.new_contact_view.$el.hide();
}) })
); );
/* eslint-enable more/no-then */ /* eslint-enable more/no-then */

@ -5,9 +5,7 @@
/* global i18n: false */ /* global i18n: false */
/* global Whisper: false */ /* global Whisper: false */
/* global textsecure: false */ /* global textsecure: false */
/* global Signal: false */ /* global clipboard: false */
/* global StringView: false */
/* global storage: false */
// eslint-disable-next-line func-names // eslint-disable-next-line func-names
(function() { (function() {
@ -104,26 +102,10 @@
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
new Whisper.FontSizeView({ el: this.$el }); new Whisper.FontSizeView({ el: this.$el });
const ourNumber = textsecure.storage.user.getNumber(); this.mainHeaderView = new Whisper.MainHeaderView({
const me = ConversationController.getOrCreate(ourNumber, 'private'); el: this.$('.main-header-placeholder'),
this.mainHeaderView = new Whisper.ReactWrapperView({ items: this.getMainHeaderItems(),
className: 'main-header-wrapper',
Component: Signal.Components.MainHeader,
props: me.format(),
}); });
const update = () => this.mainHeaderView.update(me.format());
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({ this.conversation_stack = new Whisper.ConversationStack({
el: this.$('.conversation-stack'), el: this.$('.conversation-stack'),
@ -221,20 +203,6 @@
this.$el.addClass('expired'); this.$el.addClass('expired');
} }
}, },
_getIdentityKeyViewProps() {
const identityKey = textsecure.storage.get('identityKey').pubKey;
const pubKey = StringView.arrayBufferToHex(identityKey);
const profile = storage.getLocalProfile();
const name = profile && profile.name && profile.name.displayName;
return {
identityKey: pubKey,
name,
onEditProfile: async () => {
window.Whisper.events.trigger('onEditProfile');
},
}
},
render_attributes() { render_attributes() {
return { return {
welcomeToSignal: i18n('welcomeToSignal'), welcomeToSignal: i18n('welcomeToSignal'),
@ -357,6 +325,30 @@
onClick(e) { onClick(e) {
this.closeRecording(e); this.closeRecording(e);
}, },
getMainHeaderItems() {
return [
this._mainHeaderItem('copyPublicKey', () => {
const ourNumber = textsecure.storage.user.getNumber();
clipboard.writeText(ourNumber);
const toast = new Whisper.MessageToastView({
message: i18n('copiedPublicKey'),
});
toast.$el.appendTo(this.$('.gutter'));
toast.render();
}),
this._mainHeaderItem('editDisplayName', () => {
window.Whisper.events.trigger('onEditProfile');
}),
];
},
_mainHeaderItem(textKey, onClick) {
return {
id: textKey,
text: i18n(textKey),
onClick,
};
},
}); });
Whisper.ExpiredAlertBanner = Whisper.View.extend({ Whisper.ExpiredAlertBanner = Whisper.View.extend({

@ -0,0 +1,57 @@
/* global Whisper, textsecure, ConversationController, Signal, i18n */
// eslint-disable-next-line func-names
(function() {
'use strict';
window.Whisper = window.Whisper || {};
Whisper.MainHeaderView = Whisper.View.extend({
templateName: 'main-header-placeholder',
events: {
'click .main-header-title-wrapper': 'onClick',
'click .edit-name': 'onEditProfile',
'click .copy-key': 'onCopyKey',
},
initialize(options) {
this.items = options.items || [];
this.ourNumber = textsecure.storage.user.getNumber();
const me = ConversationController.getOrCreate(this.ourNumber, 'private');
this.mainHeaderView = new Whisper.ReactWrapperView({
className: 'main-header-wrapper',
Component: Signal.Components.MainHeader,
props: me.format(),
});
const update = () => this.mainHeaderView.update(me.format());
this.listenTo(me, 'change', update);
this.render();
this.$('.main-header-title-wrapper').prepend(this.mainHeaderView.el);
this.$toggle = this.$('.main-header-content-toggle');
this.$content = this.$('.main-header-content-wrapper');
this.$content.hide();
this.registerCallbacks();
},
registerCallbacks() {
this.items.forEach(item => {
if (item.onClick) {
this.$(`#${item.id}`).click(item.onClick);
}
})
},
render_attributes() {
return {
items: this.items,
};
},
onClick() {
// Toggle section visibility
this.$content.slideToggle('fast');
this.$toggle.toggleClass('main-header-content-toggle-visible');
},
});
})();

@ -28,4 +28,13 @@
setTimeout(this.close.bind(this), 2000); setTimeout(this.close.bind(this), 2000);
}, },
}); });
Whisper.MessageToastView = Whisper.ToastView.extend({
initialize(options) {
this.message = options.message || '-';
},
render_attributes() {
return { toastMessage: this.message };
},
})
})(); })();

@ -7,6 +7,7 @@ const semver = require('semver');
const { deferredToPromise } = require('./js/modules/deferred_to_promise'); const { deferredToPromise } = require('./js/modules/deferred_to_promise');
const { app } = electron.remote; const { app } = electron.remote;
const { clipboard } = electron;
window.PROTO_ROOT = 'protos'; window.PROTO_ROOT = 'protos';
const config = require('url').parse(window.location.toString(), true).query; const config = require('url').parse(window.location.toString(), true).query;
@ -277,6 +278,8 @@ window.React = require('react');
window.ReactDOM = require('react-dom'); window.ReactDOM = require('react-dom');
window.moment = require('moment'); window.moment = require('moment');
window.clipboard = clipboard;
const Signal = require('./js/modules/signal'); const Signal = require('./js/modules/signal');
const i18n = require('./js/modules/i18n'); const i18n = require('./js/modules/i18n');
const Attachments = require('./app/attachments'); const Attachments = require('./app/attachments');

@ -33,6 +33,7 @@
flex-direction: column; flex-direction: column;
float: left; float: left;
width: 300px; width: 300px;
position: relative;
.tool-bar { .tool-bar {
margin-top: 8px; margin-top: 8px;
@ -53,6 +54,10 @@
} }
} }
.toast {
bottom: 78px;
}
.content { .content {
overflow-y: auto; overflow-y: auto;
max-height: calc(100% - 88px); max-height: calc(100% - 88px);
@ -142,51 +147,9 @@
} }
} }
.identity-key-wrapper {
background-color: $color-black-008-no-tranparency;
display: flex;
flex: 1;
height: $header-height;
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;
}
.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 { .underneathIdentityWrapper {
position: absolute; position: absolute;
top: $header-height; top: 0;
bottom: 0; bottom: 0;
left: 300px; left: 300px;
right: 0; right: 0;

@ -2180,15 +2180,73 @@
// Module: Main Header // Module: Main Header
.main-header-title-wrapper {
flex: 1;
flex-direction: row;
display: flex;
align-items: center;
cursor: pointer;
&:hover {
background-color: $color-dark-75;
}
}
.main-header-content-wrapper {
color: $color-dark-05;
div {
padding: 12px;
background-color: $color-dark-90;
cursor: pointer;
&:hover {
background-color: $color-dark-75;
}
}
}
.main-header-wrapper {
overflow-x: hidden;
flex: 1;
}
.module-main-header { .module-main-header {
height: $header-height; height: $header-height;
margin-left: 16px; padding-left: 16px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
} }
.main-header-content-toggle {
width: 3em;
line-height: 3em;
font-weight: bold;
overflow: hidden;
user-select: none;
color: white;
text-align: center;
&:after {
-webkit-transition: all .35s;
-o-transition: all .35s;
transition: all .35s;
width: 3em;
line-height: 3em;
height: 3em;
content: '\25BE';
display: inline-block;
}
}
.main-header-content-toggle-visible::after {
transform: rotate(180deg);
}
.module-main-header__app-name { .module-main-header__app-name {
font-size: 16px; font-size: 16px;
line-height: 24px; line-height: 24px;
@ -2197,6 +2255,14 @@
color: $color-dark-05; color: $color-dark-05;
} }
.module-main-header__contact-name {
font-weight: 300;
margin-left: 12px;
color: $color-dark-05;
overflow-x: auto;
flex: 1;
}
// Third-party module: react-contextmenu // Third-party module: react-contextmenu
.react-contextmenu { .react-contextmenu {

@ -6,16 +6,6 @@ body.dark-theme {
} }
.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
.conversation { .conversation {

@ -115,6 +115,7 @@ $color-dark-60: #797a7c;
$color-dark-70: #414347; $color-dark-70: #414347;
$color-dark-75: #292c33; $color-dark-75: #292c33;
$color-dark-85: #1a1c20; $color-dark-85: #1a1c20;
$color-dark-90: #121417;
$color-black-008: rgba($color-black, 0.08); $color-black-008: rgba($color-black, 0.08);
$color-black-008-no-tranparency: #ededed; $color-black-008-no-tranparency: #ededed;
$color-black-016-no-tranparency: #d9d9d9; $color-black-016-no-tranparency: #d9d9d9;

@ -374,6 +374,7 @@
<script type='text/javascript' src='../js/views/conversation_list_item_view.js' data-cover></script> <script type='text/javascript' src='../js/views/conversation_list_item_view.js' data-cover></script>
<script type='text/javascript' src='../js/views/conversation_list_view.js' data-cover></script> <script type='text/javascript' src='../js/views/conversation_list_view.js' data-cover></script>
<script type='text/javascript' src='../js/views/contact_list_view.js' data-cover></script> <script type='text/javascript' src='../js/views/contact_list_view.js' data-cover></script>
<script type='text/javascript' src='js/views/main_header_view.js'></script>
<script type='text/javascript' src='../js/views/new_group_update_view.js' data-cover></script> <script type='text/javascript' src='../js/views/new_group_update_view.js' data-cover></script>
<script type="text/javascript" src="../js/views/group_update_view.js"></script> <script type="text/javascript" src="../js/views/group_update_view.js"></script>
<script type='text/javascript' src='../js/views/attachment_view.js' data-cover></script> <script type='text/javascript' src='../js/views/attachment_view.js' data-cover></script>

@ -1,38 +0,0 @@
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 display name: <span className='identity-key_bold'>{name}</span>
</div>
}
</div>
<div
id='editProfile'
role="button"
onClick={onEditProfile}
className="identity-key-wrapper__pencil-icon"
/>
</div>
);
}
}

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import { Avatar } from './Avatar'; import { Avatar } from './Avatar';
import { ContactName } from './conversation/ContactName';
import { Localizer } from '../types/Util'; import { Localizer } from '../types/Util';
@ -25,10 +26,11 @@ export class MainHeader extends React.Component<Props> {
name, name,
phoneNumber, phoneNumber,
profileName, profileName,
onClick
} = this.props; } = this.props;
return ( return (
<div className="module-main-header"> <div role='button' className="module-main-header" onClick={onClick}>
<Avatar <Avatar
avatarPath={avatarPath} avatarPath={avatarPath}
color={color} color={color}
@ -39,7 +41,13 @@ export class MainHeader extends React.Component<Props> {
profileName={profileName} profileName={profileName}
size={28} size={28}
/> />
<div className="module-main-header__app-name">Loki Messenger</div> <div className="module-main-header__contact-name">
<ContactName
phoneNumber={phoneNumber}
profileName={profileName}
i18n={i18n}
/>
</div>
</div> </div>
); );
} }

@ -28,7 +28,7 @@ export class ContactName extends React.Component<Props> {
return ( return (
<span className={prefix}> <span className={prefix}>
{profileElement} {profileElement}
<span className={shouldShowProfile ? `${prefix}__profile-number` : ''}> <span title={phoneNumber} className={shouldShowProfile ? `${prefix}__profile-number` : ''}>
<Emojify text={title} i18n={i18n} /> <Emojify text={title} i18n={i18n} />
</span> </span>
</span> </span>

Loading…
Cancel
Save