Merge branch 'brand-redesign' into clearnet

This commit is contained in:
Audric Ackermann 2020-01-22 17:59:08 +11:00
commit 293eca0509
53 changed files with 694 additions and 357 deletions

View file

@ -63,7 +63,7 @@ yarn install --frozen-lockfile # Install and build dependencies (this will take
yarn grunt # Generate final JS and CSS assets
yarn icon-gen # Generate full set of icons for Electron
yarn test # A good idea to make sure tests run first
yarn start # Start Loki Messenger!
yarn start # Start Session Messenger!
```
You'll need to restart the application regularly to see your changes, as there
@ -84,7 +84,7 @@ yarn grunt dev # runs until you stop it, re-generating built assets on file chan
## Additional storage profiles
Since there is no registration for Loki Messenger, you can create as many accounts as you
Since there is no registration for Session Messenger, you can create as many accounts as you
can public keys. To test the P2P functionality on the same machine, however, requries
that each client binds their message server to a different port.

View file

@ -1,8 +1,8 @@
# Loki Messenger
# Session Messenger
[![Build Status](https://travis-ci.org/loki-project/loki-messenger.svg?branch=development)](https://travis-ci.org/loki-project/loki-messenger)
Loki Messenger allows for truly decentralized, end to end, and private encrypted chats. Loki Messenger is built to handle both online and fully Asynchronous offline messages. Loki messenger implements the Signal protocol for message encryption. Our Client interface is a fork of [Signal Messenger](https://signal.org/). All communication that passes through Loki messenger is routed through [Lokinet](https://github.com/loki-project/loki-network).
Session Messenger allows for truly decentralized, end to end, and private encrypted chats. Session Messenger is built to handle both online and fully Asynchronous offline messages. Loki messenger implements the Signal protocol for message encryption. Our Client interface is a fork of [Session Messenger](https://signal.org/). All communication that passes through Loki messenger is routed through [Lokinet](https://github.com/loki-project/loki-network).
## Summary
@ -14,11 +14,11 @@ If Alice and Bob are both online they can simply resolve each others public keys
**Offline messages**
Offline messaging uses Swarms, given any users public key the user can resolve a public key to a specific grouping of Service Nodes (AKA Swarm) each user in Loki Messenger belongs to a Swarm. When routing a message offline the user selects a Service node in the destination users Swarm, when the user comes online they query any node in their Swarm, if the Swarm is holding any messages for the user they disseminate those messages to the user.
Offline messaging uses Swarms, given any users public key the user can resolve a public key to a specific grouping of Service Nodes (AKA Swarm) each user in Session Messenger belongs to a Swarm. When routing a message offline the user selects a Service node in the destination users Swarm, when the user comes online they query any node in their Swarm, if the Swarm is holding any messages for the user they disseminate those messages to the user.
![Swarm Messaging](https://i.imgur.com/o13Knds.png)
Spam protections for Loki Messenger are based on a Proof of Work which is attached to any message that exceeds a default size or Time To Live, this process is discussed further in the [Loki whitepaper](https://loki.network/whitepaper).
Spam protections for Session Messenger are based on a Proof of Work which is attached to any message that exceeds a default size or Time To Live, this process is discussed further in the [Loki whitepaper](https://loki.network/whitepaper).
## Want to Contribute? Found a Bug or Have a feature request?

View file

@ -52,7 +52,7 @@
"description": "Application menu command to show all application windows"
},
"appMenuQuit": {
"message": "Quit Loki Messenger",
"message": "Quit Session Messenger",
"description": "Application menu command to close the application"
},
"editMenuUndo": {

View file

@ -52,7 +52,7 @@
"description": "Application menu command to show all application windows"
},
"appMenuQuit": {
"message": "Quit Loki Messenger",
"message": "Quit Session Messenger",
"description": "Application menu command to close the application"
},
"editMenuUndo": {

View file

@ -52,7 +52,7 @@
"description": "Application menu command to show all application windows"
},
"appMenuQuit": {
"message": "Opustit Loki Messenger",
"message": "Opustit Session Messenger",
"description": "Application menu command to close the application"
},
"editMenuUndo": {

View file

@ -66,7 +66,7 @@
"description": "Application menu command to show all application windows"
},
"appMenuQuit": {
"message": "Quit Loki Messenger",
"message": "Quit Session Messenger",
"description": "Application menu command to close the application"
},
"editMenuUndo": {
@ -265,7 +265,7 @@
"Header shown on the screen at the end of a successful import process"
},
"importCompleteStartButton": {
"message": "Start using Loki Messenger",
"message": "Start using Session Messenger",
"description":
"Button shown at end of successful import process, nothing left but a restart"
},
@ -719,12 +719,12 @@
"Item under the Help menu, takes you to GitHub new issue form (title case)"
},
"signalDesktopPreferences": {
"message": "Loki Messenger Preferences",
"message": "Session Messenger Preferences",
"description":
"Title of the window that pops up with Signal Desktop preferences in it"
},
"aboutSignalDesktop": {
"message": "About Loki Messenger",
"message": "About Session Messenger",
"description": "Item under the Help menu, which opens a small about window"
},
"speech": {
@ -745,7 +745,7 @@
"description": "Command in the tray icon menu, to quit the application"
},
"lokiMessenger": {
"message": "Loki Messenger"
"message": "Session Messenger"
},
"search": {
"message": "Search",
@ -895,7 +895,7 @@
},
"audioPermissionNeeded": {
"message":
"To send audio messages, allow Loki Messenger to access your microphone.",
"To send audio messages, allow Session Messenger to access your microphone.",
"description":
"Shown if the user attempts to send an audio message without audio permssions turned on"
},
@ -952,6 +952,9 @@
"cancel": {
"message": "Cancel"
},
"copy": {
"message": "Copy"
},
"skip": {
"message": "Skip"
},
@ -1266,7 +1269,7 @@
}
},
"installWelcome": {
"message": "Welcome to Loki Messenger",
"message": "Welcome to Session Messenger",
"description": "Welcome title on the install page"
},
"installTagline": {
@ -1275,12 +1278,12 @@
"Tagline displayed under 'installWelcome' string on the install page"
},
"linkYourPhone": {
"message": "Link your phone to Loki Messenger",
"message": "Link your phone to Session Messenger",
"description":
"Shown on the front page when the application first starst, above the QR code"
},
"signalSettings": {
"message": "Loki Messenger Settings",
"message": "Session Messenger Settings",
"description":
"Used in the guidance to help people find the 'link new device' area of their Signal mobile app"
},
@ -1491,7 +1494,7 @@
},
"expiredWarning": {
"message":
"This version of Loki Messenger has expired. Please upgrade to the latest version to continue messaging.",
"This version of Session Messenger has expired. Please upgrade to the latest version to continue messaging.",
"description":
"Warning notification that this version of the app has expired"
},
@ -2153,6 +2156,9 @@
"description":
"Button action that the user can click to view their unique seed"
},
"yourSessionID": {
"message": "Your Session ID"
},
"setAccountPasswordTitle": {
"message": "Set Account Password",
"description": "Prompt for user to set account password in settings view"
@ -2244,6 +2250,11 @@
"description":
"A toast message telling the user that the mnemonic seed was copied"
},
"copiedSessionID": {
"message": "Copied Session ID to clipboard",
"description":
"A toast message telling the user that their Session ID was copied"
},
"passwordViewTitle": {
"message": "Type in your password",
"description":
@ -2410,7 +2421,7 @@
},
"editProfileModalTitle": {
"message": "Edit Profile",
"message": "Profile",
"description": "Title for the Edit Profile modal"
},
@ -2502,7 +2513,7 @@
},
"devicePairingHeader": {
"message":
"Open the Loki Messenger App on your primary device and select Device Pairing from the main menu. Then, enter your Session ID below to sign in."
"Open the Session Messenger App on your primary device and select Device Pairing from the main menu. Then, enter your Session ID below to sign in."
},
"enterSessionIDHere": {
"message": "Enter your Session ID here"

View file

@ -36,7 +36,7 @@
"description": "Application menu command to show all application windows"
},
"appMenuQuit": {
"message": "Quit Loki Messenger",
"message": "Quit Session Messenger",
"description": "Application menu command to close the application"
},
"editMenuUndo": {

View file

@ -52,7 +52,7 @@
"description": "Application menu command to show all application windows"
},
"appMenuQuit": {
"message": "Quit Loki Messenger",
"message": "Quit Session Messenger",
"description": "Application menu command to close the application"
},
"editMenuUndo": {

View file

@ -52,7 +52,7 @@
"description": "Application menu command to show all application windows"
},
"appMenuQuit": {
"message": "Quit Loki Messenger",
"message": "Quit Session Messenger",
"description": "Application menu command to close the application"
},
"editMenuUndo": {

View file

@ -52,7 +52,7 @@
"description": "Application menu command to show all application windows"
},
"appMenuQuit": {
"message": "Quit Loki Messenger",
"message": "Quit Session Messenger",
"description": "Application menu command to close the application"
},
"editMenuUndo": {

View file

@ -52,7 +52,7 @@
"description": "Application menu command to show all application windows"
},
"appMenuQuit": {
"message": "Quit Loki Messenger",
"message": "Quit Session Messenger",
"description": "Application menu command to close the application"
},
"editMenuUndo": {

View file

@ -52,7 +52,7 @@
"description": "Application menu command to show all application windows"
},
"appMenuQuit": {
"message": "Quit Loki Messenger",
"message": "Quit Session Messenger",
"description": "Application menu command to close the application"
},
"editMenuUndo": {

View file

@ -52,7 +52,7 @@
"description": "Application menu command to show all application windows"
},
"appMenuQuit": {
"message": "Quit Loki Messenger",
"message": "Quit Session Messenger",
"description": "Application menu command to close the application"
},
"editMenuUndo": {

View file

@ -52,7 +52,7 @@
"description": "Application menu command to show all application windows"
},
"appMenuQuit": {
"message": "Quit Loki Messenger",
"message": "Quit Session Messenger",
"description": "Application menu command to close the application"
},
"editMenuUndo": {

View file

@ -52,7 +52,7 @@
"description": "Application menu command to show all application windows"
},
"appMenuQuit": {
"message": "Quit Loki Messenger",
"message": "Quit Session Messenger",
"description": "Application menu command to close the application"
},
"editMenuUndo": {

View file

@ -16,17 +16,12 @@ exports.createTemplate = (options, messages) => {
setupWithImport,
showAbout,
showDebugLog,
showSettings,
} = options;
const template = [
{
label: messages.mainMenuFile.message,
submenu: [
{
label: messages.mainMenuSettings.message,
click: showSettings,
},
{
type: 'separator',
},
@ -193,7 +188,6 @@ function updateForMac(template, messages, options) {
setupAsStandalone,
setupWithImport,
showAbout,
showSettings,
showWindow,
} = options;
@ -242,11 +236,6 @@ function updateForMac(template, messages, options) {
{
type: 'separator',
},
{
label: messages.mainMenuSettings.message,
accelerator: 'CommandOrControl+,',
click: showSettings,
},
{
type: 'separator',
},

View file

@ -19,7 +19,7 @@
script-src 'self';
style-src 'self' 'unsafe-inline';"
>
<title>Loki Messenger</title>
<title>Session Messenger</title>
<link href='images/loki/loki_icon_128.png' rel='shortcut icon'>
<link href="stylesheets/manifest.css" rel="stylesheet" type="text/css" />
@ -196,15 +196,15 @@
<div class="content">
<div class="betaDisclaimerView" style="display: none;">
<h2>
Thanks for testing Loki Messenger!
Thanks for testing Session Messenger!
</h2>
<p>
Thanks for testing Loki Messenger! This software is a beta version of the full Loki Messenger software suite, and so is missing some of the features the full version will have.
Thanks for testing Session Messenger! This software is a beta version of the full Session Messenger software suite, and so is missing some of the features the full version will have.
</p>
<p>
<b>
This version of Loki Messenger provides no guarantees of metadata privacy.
This version of Session Messenger provides no guarantees of metadata privacy.
</b>
</p>
@ -217,7 +217,7 @@
</p>
<p>
However, no one except you and your intended recipients will be able to see the contents of your messages. We recommend using existing methods, like Tor or I2P to mask your IP address while using Loki Messenger beta version.
However, no one except you and your intended recipients will be able to see the contents of your messages. We recommend using existing methods, like Tor or I2P to mask your IP address while using Session Messenger beta version.
</p>
<p>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 353 KiB

After

Width:  |  Height:  |  Size: 0 B

BIN
build/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View file

@ -321,7 +321,7 @@
window.Events = {
getDeviceName: () => textsecure.storage.user.getDeviceName(),
getThemeSetting: () => storage.get('theme-setting', 'dark'),
getThemeSetting: () => 'dark', // storage.get('theme-setting', 'dark')
setThemeSetting: value => {
storage.put('theme-setting', value);
onChangeTheme();
@ -834,8 +834,106 @@
confirmDialog.render();
};
window.showQRDialog = window.owsDesktopApp.appView.showQRDialog;
window.showSeedDialog = window.owsDesktopApp.appView.showSeedDialog;
window.showPasswordDialog = window.owsDesktopApp.appView.showPasswordDialog;
window.showEditProfileDialog = async () => {
const ourNumber = window.storage.get('primaryDevicePubKey');
const conversation = await ConversationController.getOrCreateAndWait(
ourNumber,
'private'
);
const readFile = attachment =>
new Promise((resolve, reject) => {
const fileReader = new FileReader();
fileReader.onload = e => {
const data = e.target.result;
resolve({
...attachment,
data,
size: data.byteLength,
});
};
fileReader.onerror = reject;
fileReader.onabort = reject;
fileReader.readAsArrayBuffer(attachment.file);
});
const avatarPath = conversation.getAvatarPath();
const profile = conversation.getLokiProfile();
const displayName = profile && profile.displayName;
if (appView) {
appView.showEditProfileDialog({
profileName: displayName,
pubkey: ourNumber,
avatarPath,
avatarColor: conversation.getColor(),
onOk: async (newName, avatar) => {
let newAvatarPath = '';
let url = null;
let profileKey = null;
if (avatar) {
const data = await readFile({ file: avatar });
// For simplicity we use the same attachment pointer that would send to
// others, which means we need to wait for the database response.
// To avoid the wait, we create a temporary url for the local image
// and use it until we the the response from the server
const tempUrl = window.URL.createObjectURL(avatar);
conversation.setLokiProfile({ displayName: newName });
conversation.set('avatar', tempUrl);
// Encrypt with a new key every time
profileKey = libsignal.crypto.getRandomBytes(32);
const encryptedData = await textsecure.crypto.encryptProfile(
data.data,
profileKey
);
const avatarPointer = await textsecure.messaging.uploadAvatar({
...data,
data: encryptedData,
size: encryptedData.byteLength,
});
({ url } = avatarPointer);
storage.put('profileKey', profileKey);
conversation.set('avatarPointer', url);
const upgraded = await Signal.Migrations.processNewAttachment({
isRaw: true,
data: data.data,
url,
});
newAvatarPath = upgraded.path;
}
// Replace our temporary image with the attachment pointer from the server:
conversation.set('avatar', null);
conversation.setLokiProfile({
displayName: newName,
avatar: newAvatarPath,
});
// inform all your registered public servers
// could put load on all the servers
// if they just keep changing their names without sending messages
// so we could disable this here
// or least it enable for the quickest response
window.lokiPublicChatAPI.setProfileName(newName);
window
.getConversations()
.filter(convo => convo.isPublic() && !convo.isRss())
.forEach(convo =>
convo.trigger('ourAvatarChanged', { url, profileKey })
);
},
});
}
};
window.generateID = () =>
Math.random()
@ -921,8 +1019,13 @@
};
window.toggleMenuBar = () => {
const newValue = !window.getSettingValue('hide-menu-bar');
window.Events.setHideMenuBar(newValue);
const current = window.getSettingValue('hide-menu-bar');
if (current === undefined) {
window.Events.setHideMenuBar(false);
return;
}
window.Events.setHideMenuBar(!current);
};
window.toggleSpellCheck = () => {
@ -1057,104 +1160,6 @@
});
});
Whisper.events.on('onEditProfile', async () => {
const ourNumber = window.storage.get('primaryDevicePubKey');
const conversation = await ConversationController.getOrCreateAndWait(
ourNumber,
'private'
);
const readFile = attachment =>
new Promise((resolve, reject) => {
const fileReader = new FileReader();
fileReader.onload = e => {
const data = e.target.result;
resolve({
...attachment,
data,
size: data.byteLength,
});
};
fileReader.onerror = reject;
fileReader.onabort = reject;
fileReader.readAsArrayBuffer(attachment.file);
});
const avatarPath = conversation.getAvatarPath();
const profile = conversation.getLokiProfile();
const displayName = profile && profile.displayName;
if (appView) {
appView.showEditProfileDialog({
profileName: displayName,
pubkey: ourNumber,
avatarPath,
avatarColor: conversation.getColor(),
onOk: async (newName, avatar) => {
let newAvatarPath = '';
let url = null;
let profileKey = null;
if (avatar) {
const data = await readFile({ file: avatar });
// For simplicity we use the same attachment pointer that would send to
// others, which means we need to wait for the database response.
// To avoid the wait, we create a temporary url for the local image
// and use it until we the the response from the server
const tempUrl = window.URL.createObjectURL(avatar);
conversation.setLokiProfile({ displayName: newName });
conversation.set('avatar', tempUrl);
// Encrypt with a new key every time
profileKey = libsignal.crypto.getRandomBytes(32);
const encryptedData = await textsecure.crypto.encryptProfile(
data.data,
profileKey
);
const avatarPointer = await textsecure.messaging.uploadAvatar({
...data,
data: encryptedData,
size: encryptedData.byteLength,
});
({ url } = avatarPointer);
storage.put('profileKey', profileKey);
conversation.set('avatarPointer', url);
const upgraded = await Signal.Migrations.processNewAttachment({
isRaw: true,
data: data.data,
url,
});
newAvatarPath = upgraded.path;
}
// Replace our temporary image with the attachment pointer from the server:
conversation.set('avatar', null);
conversation.setLokiProfile({
displayName: newName,
avatar: newAvatarPath,
});
// inform all your registered public servers
// could put load on all the servers
// if they just keep changing their names without sending messages
// so we could disable this here
// or least it enable for the quickest response
window.lokiPublicChatAPI.setProfileName(newName);
window
.getConversations()
.filter(convo => convo.isPublic() && !convo.isRss())
.forEach(convo =>
convo.trigger('ourAvatarChanged', { url, profileKey })
);
},
});
}
});
Whisper.events.on('onShowUserDetails', async ({ userPubKey }) => {
const isMe = userPubKey === textsecure.storage.user.getNumber();

View file

@ -6,7 +6,7 @@ const got = require('got');
const BASE_URL = 'https://debuglogs.org';
const VERSION = window.getVersion();
const USER_AGENT = `Loki Messenger ${VERSION}`;
const USER_AGENT = `Session Messenger ${VERSION}`;
// Workaround: Submitting `FormData` using native `FormData::submit` procedure
// as integration with `got` results in S3 error saying we havent set the

View file

@ -59,8 +59,8 @@ const {
DevicePairingDialog,
} = require('../../ts/components/DevicePairingDialog');
const {
SessionSettings,
} = require('../../ts/components/session/SessionSettings');
SettingsView,
} = require('../../ts/components/session/settings/SessionSettings');
const { SessionToast } = require('../../ts/components/session/SessionToast');
const { SessionToggle } = require('../../ts/components/session/SessionToggle');
const { SessionModal } = require('../../ts/components/session/SessionModal');
@ -273,7 +273,7 @@ exports.setup = (options = {}) => {
ContactName,
ConversationHeader,
SessionChannelSettings,
SessionSettings,
SettingsView,
EmbeddedContact,
Emojify,
FriendRequest,

View file

@ -222,7 +222,7 @@ function _promiseAjax(providedUrl, options) {
method: options.type,
body: options.data || null,
headers: {
'User-Agent': 'Loki Messenger',
'User-Agent': 'Session Messenger',
'X-Loki-Messenger-Agent': 'OWD',
...options.headers,
},

View file

@ -108,7 +108,7 @@
const last = this.last().toJSON();
switch (userSetting) {
case SettingNames.COUNT:
title = 'Loki Messenger';
title = 'Session Messenger';
if (last.isFriendRequest) {
message = `Friend request ${last.friendRequestType}`;

View file

@ -25,7 +25,7 @@
},
applyTheme() {
const iOS = storage.get('userAgent') === 'OWI';
const theme = storage.get('theme-setting') || 'dark';
const theme = 'dark'; // storage.get('theme-setting') || 'dark';
this.$el
.removeClass('light-theme')
.removeClass('dark-theme')
@ -38,7 +38,7 @@
}
},
applyHideMenu() {
const hideMenuBar = storage.get('hide-menu-bar', false);
const hideMenuBar = storage.get('hide-menu-bar', true);
window.setAutoHideMenuBar(hideMenuBar);
window.setMenuBarVisibility(!hideMenuBar);
},

View file

@ -13,7 +13,7 @@
render() {
this.settingsView = new Whisper.ReactWrapperView({
className: 'session-settings',
Component: window.Signal.Components.SessionSettings,
Component: window.Signal.Components.SettingsView,
props: {
i18n,
},

View file

@ -75,7 +75,7 @@ describe('Snode Channel', () => {
});
it('should encrypt data correctly', async () => {
// message sent by Loki Messenger
// message sent by Session Messenger
const snode = await generateSnodeKeysAndAddress();
const messageSent = 'I am Groot';
const textEncoder = new TextEncoder();
@ -133,7 +133,7 @@ describe('Snode Channel', () => {
const encryptedBase64 = dcodeIO.ByteBuffer.wrap(encrypted).toString(
'base64'
);
// message received by Loki Messenger
// message received by Session Messenger
const decrypted = await channel.decrypt(snode.address, encryptedBase64);
assert.strictEqual(messageSent, decrypted);
});

View file

@ -321,7 +321,7 @@ OutgoingMessage.prototype = {
return Promise.all(
devicesPubKeys.map(async devicePubKey => {
// Loki Messenger doesn't use the deviceId scheme, it's always 1.
// Session Messenger doesn't use the deviceId scheme, it's always 1.
// Instead, there are multiple device public keys.
const deviceId = 1;
const updatedDevices = await this.getStaleDeviceIdsForNumber(

View file

@ -1,6 +1,6 @@
{
"name": "loki-messenger-desktop",
"productName": "Loki Messenger",
"productName": "Session Messenger",
"description": "Private messaging from your desktop",
"repository": "https://github.com/loki-project/loki-messenger.git",
"version": "1.0.0-beta10",
@ -22,6 +22,7 @@
"generate": "yarn icon-gen && yarn grunt",
"build": "electron-builder --config.extraMetadata.environment=$SIGNAL_ENV",
"build-release": "export SIGNAL_ENV=production && npm run build -- --config.directories.output=release",
"make:linux:x64:appimage": "electron-builder build --linux appimage --x64",
"sign-release": "node ts/updater/generateSignature.js",
"build-module-protobuf": "pbjs --target static-module --wrap commonjs --out ts/protobuf/compiled.js protos/*.proto && pbts --out ts/protobuf/compiled.d.ts ts/protobuf/compiled.js",
"clean-module-protobuf": "rm -f ts/protobuf/compiled.d.ts ts/protobuf/compiled.js",
@ -66,6 +67,7 @@
"classnames": "2.2.5",
"color": "^3.1.2",
"config": "1.28.1",
"cross-env": "^6.0.3",
"dompurify": "^2.0.7",
"electron-context-menu": "^0.15.0",
"electron-editor-context-menu": "1.1.1",
@ -239,7 +241,7 @@
"linux": {
"category": "Network",
"desktop": {
"StartupWMClass": "Loki Messenger"
"StartupWMClass": "Session Messenger"
},
"asarUnpack": "node_modules/spellchecker/vendor/hunspell_dictionaries",
"target": [

View file

@ -27,16 +27,16 @@ const PRODUCTION_NAME = 'loki-messenger-desktop';
const BETA_NAME = 'loki-messenger-desktop-beta';
const PRODUCT_NAME_PATH = 'productName';
const PRODUCTION_PRODUCT_NAME = 'Loki Messenger';
const BETA_PRODUCT_NAME = 'Loki Messenger Beta';
const PRODUCTION_PRODUCT_NAME = 'Session Messenger';
const BETA_PRODUCT_NAME = 'Session Messenger Beta';
const APP_ID_PATH = 'build.appId';
const PRODUCTION_APP_ID = 'com.loki-project.messenger-desktop';
const BETA_APP_ID = 'com.loki-project.messenger-desktop-beta';
const STARTUP_WM_CLASS_PATH = 'build.linux.desktop.StartupWMClass';
const PRODUCTION_STARTUP_WM_CLASS = 'Loki Messenger';
const BETA_STARTUP_WM_CLASS = 'Loki Messenger Beta';
const PRODUCTION_STARTUP_WM_CLASS = 'Session Messenger';
const BETA_STARTUP_WM_CLASS = 'Session Messenger Beta';
// -------

View file

@ -27,7 +27,7 @@
font-weight: bold;
}
@font-face {
font-family: 'SFPro';
font-family: 'SF Pro Text';
src: url('../fonts/SFProText-Regular.ttf') format('truetype');
}
@ -87,6 +87,12 @@ $session-margin-sm: 10px;
$session-margin-md: 15px;
$session-margin-lg: 20px;
$session-font-xs: 11px;
$session-font-sm: 13px;
$session-font-md: 15px;
$session-font-lg: 18px;
$session-font-xl: 24px;
$session-search-input-height: 34px;
$main-view-header-height: 85px;
@ -322,7 +328,7 @@ $session_message-container-border-radius: 5px;
height: 45px;
line-height: 40px;
padding: 0;
font-size: 15px;
font-size: $session-font-md;
font-family: $session-font-family;
border-radius: 500px;
@ -340,7 +346,7 @@ $session_message-container-border-radius: 5px;
height: 33px;
padding: 0px 18px;
line-height: 33px;
font-size: 13px;
font-size: $session-font-sm;
}
&.square,
@ -415,7 +421,7 @@ $session_message-container-border-radius: 5px;
.notification-count {
position: absolute;
font-size: 12px;
font-size: $session-font-xs;
font-family: $session-font-family;
top: 20px;
right: 20px;
@ -581,8 +587,8 @@ label {
}
.title {
font-size: 15px;
line-height: 13px;
font-size: $session-font-md;
line-height: $session-font-sm;
margin-bottom: $session-margin-sm;
padding-top: 0px;
color: $session-color-white;
@ -590,7 +596,7 @@ label {
}
.description {
font-size: 12px;
font-size: $session-font-xs;
@include session-color-subtle($session-color-white);
}
@ -640,15 +646,30 @@ label {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
padding: $session-margin-lg;
font-family: 'Wasa';
text-align: center;
line-height: 18px;
font-size: 15px;
font-size: $session-font-md;
font-weight: 700;
&.reverse {
flex-direction: row-reverse;
.session-modal__header__close > div {
float: right;
}
.session-modal__header__icons > div {
float: left;
padding-left: 0px;
padding-right: 10px;
}
}
&__icons,
&__close {
width: 60px;
@ -668,8 +689,8 @@ label {
&__body {
padding: 0px $session-margin-lg $session-margin-lg $session-margin-lg;
font-family: 'Wasa';
line-height: 16px;
font-size: 13px;
line-height: $session-font-md;
font-size: $session-font-sm;
.message {
text-align: center;
@ -703,7 +724,7 @@ label {
font-family: monospace;
font-style: normal;
font-size: 11px;
font-size: $session-font-xs;
}
}
@ -715,7 +736,7 @@ label {
}
&-main-message {
font-size: 15px;
font-size: $session-font-md;
}
&-sub-message {
margin-top: 5px;
@ -775,7 +796,7 @@ label {
color: $session-color-white;
font-family: 'Wasa';
font-size: 12px;
font-size: $session-font-sm;
line-height: $session-icon-size-sm;
font-weight: 700;
@ -811,7 +832,7 @@ label {
color: $session-color-white;
font-family: 'Wasa';
font-size: 10px;
font-size: $session-font-xs;
line-height: $session-icon-size-sm;
font-weight: 700;
@ -837,10 +858,139 @@ label {
}
}
.edit-profile-dialog .image-upload-section {
position: absolute;
margin-top: 50px;
margin-left: 75px;
.edit-profile-dialog {
.session-modal__header__title {
font-size: $session-font-lg;
}
.session-modal {
width: $session-modal-size-md;
&__header {
height: 68.45px;
}
}
.avatar-center-inner {
position: relative;
.module-avatar {
box-shadow: 0 0 23px 0 rgba($session-color-black, 0.78);
}
.qr-view-button {
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
right: -3px;
height: 26px;
width: 26px;
border-radius: 50%;
padding-top: 3px;
background-color: $session-color-white;
transition: $session-transition-duration;
&:hover {
filter: brightness(90%);
}
.session-icon-button {
opacity: 1;
}
}
}
.image-upload-section {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
cursor: pointer;
width: 80px;
height: 80px;
border-radius: 100%;
background-color: rgba($session-color-black, 0.72);
box-shadow: 0px 0px 3px 0.5px rgba(0, 0, 0, 0.75);
opacity: 0;
transition: $session-transition-duration;
&:after {
content: 'Edit';
}
&:hover {
opacity: 1;
}
}
.qr-image {
display: flex;
justify-content: center;
svg {
width: 135px;
height: 135px;
border-radius: 3px;
padding: $session-margin-xs;
background-color: $session-color-white;
}
}
.session-id-section {
display: flex;
align-items: center;
flex-direction: column;
.panel-text-divider {
margin-top: 35px;
margin-bottom: 35px;
}
&-display {
text-align: center;
word-break: break-all;
font-size: $session-font-md;
padding: 0px $session-margin-lg;
font-family: 'SF Pro Text';
font-weight: 100;
color: rgba($session-color-white, 0.8);
font-size: $session-font-md;
padding: 0px $session-margin-sm;
}
.session-button {
width: 148px;
}
}
.profile-name {
display: flex;
justify-content: center;
margin-top: $session-margin-lg;
&-input {
height: 38px;
width: 142px;
border-radius: 5px;
text-align: center;
font-size: $session-font-md;
background-color: $session-shade-5 !important;
}
&-uneditable {
display: flex;
align-items: center;
justify-content: center;
margin-left: $session-margin-lg;
p {
font-size: $session-font-md;
padding: 0px $session-margin-sm;
}
}
}
}
.conversation-loader {
@ -932,7 +1082,7 @@ label {
&-title {
line-height: $main-view-header-height;
font-weight: bold;
font-size: 18px;
font-size: $session-font-lg;
text-align: center;
flex-grow: 1;
}
@ -944,7 +1094,7 @@ label {
}
&-item {
font-size: 15px;
font-size: $session-font-md;
color: $session-color-white;
background-color: $session-shade-1;
@ -963,12 +1113,12 @@ label {
&__title {
line-height: 1.7;
font-size: 16px;
font-size: $session-font-lg;
font-weight: bold;
}
&__description {
font-size: 13px;
font-size: $session-font-sm;
font-weight: 100;
@include session-color-subtle($session-color-white);
}
@ -1014,7 +1164,7 @@ label {
border: none;
border-radius: 2px;
text-align: center;
font-size: 25px;
font-size: $session-font-xl;
letter-spacing: 5px;
font-family: 'SF Pro Text';
}
@ -1025,6 +1175,8 @@ label {
#qr svg {
width: $session-modal-size-sm;
height: $session-modal-size-sm;
padding: $session-margin-xs;
background-color: $session-color-white;
border-radius: 3px;
}
@ -1048,7 +1200,7 @@ label {
.discussion-container {
.module-message {
font-family: SFPro;
font-family: 'SF Pro Text';
border-radius: 5px;
}
}
@ -1059,7 +1211,7 @@ label {
border: none;
margin: 0px;
padding: 0px $session-margin-lg;
font-size: 15px;
font-size: $session-font-md;
line-height: 60px;
@include session-color-subtle($session-color-white);
@ -1120,10 +1272,6 @@ label {
background-color: $session-color-white;
border-color: $session-color-white;
}
label:before {
transition: all $session-transition-duration ease;
}
}
.user-details-dialog {
.session-id-editable {
@ -1173,7 +1321,7 @@ input {
width: 600px;
&__header {
font-size: 17px;
font-size: $session-font-lg;
}
&__body > div:first-child {

View file

@ -1,9 +1,9 @@
[
{
"label": "Loki Messenger",
"label": "Session Messenger",
"submenu": [
{
"label": "About Loki Messenger",
"label": "About Session Messenger",
"click": null
},
{
@ -33,7 +33,7 @@
"type": "separator"
},
{
"label": "Quit Loki Messenger",
"label": "Quit Session Messenger",
"role": "quit"
}
]

View file

@ -1,9 +1,9 @@
[
{
"label": "Loki Messenger",
"label": "Session Messenger",
"submenu": [
{
"label": "About Loki Messenger",
"label": "About Session Messenger",
"click": null
},
{
@ -33,7 +33,7 @@
"type": "separator"
},
{
"label": "Quit Loki Messenger",
"label": "Quit Session Messenger",
"role": "quit"
}
]

View file

@ -21,7 +21,7 @@
"type": "separator"
},
{
"label": "Quit Loki Messenger",
"label": "Quit Session Messenger",
"role": "quit"
}
]
@ -138,7 +138,7 @@
"type": "separator"
},
{
"label": "About Loki Messenger",
"label": "About Session Messenger",
"click": null
}
]

View file

@ -10,7 +10,7 @@
"type": "separator"
},
{
"label": "Quit Loki Messenger",
"label": "Quit Session Messenger",
"role": "quit"
}
]
@ -127,7 +127,7 @@
"type": "separator"
},
{
"label": "About Loki Messenger",
"label": "About Session Messenger",
"click": null
}
]

View file

@ -146,15 +146,15 @@
<div class="content">
<div class="betaDisclaimerView" style="display: none;">
<h2>
Thanks for testing Loki Messenger!
Thanks for testing Session Messenger!
</h2>
<p>
Thanks for testing Loki Messenger! This software is a beta version of the full Loki Messenger software suite, and so is missing some of the features the full version will have.
Thanks for testing Session Messenger! This software is a beta version of the full Session Messenger software suite, and so is missing some of the features the full version will have.
</p>
<p>
<b>
This version of Loki Messenger provides no guarantees of metadata privacy.
This version of Session Messenger provides no guarantees of metadata privacy.
</b>
</p>
@ -167,7 +167,7 @@
</p>
<p>
However, no one except you and your intended recipients will be able to see the contents of your messages. We recommend using existing methods, like Tor or I2P to mask your IP address while using Loki Messenger beta version.
However, no one except you and your intended recipients will be able to see the contents of your messages. We recommend using existing methods, like Tor or I2P to mask your IP address while using Session Messenger beta version.
</p>
<p>

View file

@ -131,14 +131,9 @@ export class DevicePairingDialog extends React.Component<Props, State> {
}
public renderQrCodeView() {
const theme = window.Events.getThemeSetting();
const requestReceived = this.hasReceivedRequests();
const title = window.i18n('pairingDevice');
// Foreground equivalent to .session-modal background color
const bgColor = 'rgba(0, 0, 0, 0)';
const fgColor = theme === 'dark' ? '#FFFFFF' : '#1B1B1B';
return (
<SessionModal title={title} onOk={() => null} onClose={this.closeDialog}>
<div className="session-modal__centered">
@ -149,11 +144,9 @@ export class DevicePairingDialog extends React.Component<Props, State> {
</small>
<div className="spacer-lg" />
<div id="qr">
<div className="qr-image">
<QRCode
value={window.textsecure.storage.user.getNumber()}
bgColor={bgColor}
fgColor={fgColor}
level="L"
/>
</div>

View file

@ -1,8 +1,14 @@
import React from 'react';
import classNames from 'classnames';
import { QRCode } from 'react-qr-svg';
import { Avatar } from './Avatar';
import { SessionButton, SessionButtonColor } from './session/SessionButton';
import {
SessionButton,
SessionButtonColor,
SessionButtonType,
} from './session/SessionButton';
import {
SessionIconButton,
SessionIconSize,
@ -28,9 +34,9 @@ interface Props {
interface State {
profileName: string;
errorDisplayed: boolean;
errorMessage: string;
setProfileName: string;
avatar: string;
mode: 'default' | 'edit' | 'qr';
}
export class EditProfileDialog extends React.Component<Props, State> {
@ -42,15 +48,14 @@ export class EditProfileDialog extends React.Component<Props, State> {
this.onNameEdited = this.onNameEdited.bind(this);
this.closeDialog = this.closeDialog.bind(this);
this.onClickOK = this.onClickOK.bind(this);
this.showError = this.showError.bind(this);
this.onKeyUp = this.onKeyUp.bind(this);
this.onFileSelected = this.onFileSelected.bind(this);
this.state = {
profileName: this.props.profileName,
errorDisplayed: false,
errorMessage: 'placeholder',
setProfileName: this.props.profileName,
avatar: this.props.avatarPath,
mode: 'default',
};
this.inputEl = React.createRef();
@ -61,25 +66,86 @@ export class EditProfileDialog extends React.Component<Props, State> {
public render() {
const i18n = this.props.i18n;
const cancelText = i18n('cancel');
const okText = i18n('ok');
const placeholderText = i18n('profileName');
const viewDefault = this.state.mode === 'default';
const viewEdit = this.state.mode === 'edit';
const viewQR = this.state.mode === 'qr';
const sessionID = window.textsecure.storage.user.getNumber();
const errorMessageClasses = classNames(
'error-message',
this.state.errorDisplayed ? 'error-shown' : 'error-faded'
);
const backButton =
viewEdit || viewQR
? [
{
iconType: SessionIconType.Chevron,
iconRotation: 90,
onClick: () => {
this.setState({ mode: 'default' });
},
},
]
: undefined;
return (
<SessionModal
title={i18n('editProfileModalTitle')}
onOk={this.onClickOK}
onClose={this.closeDialog}
headerReverse={viewEdit || viewQR}
headerIconButtons={backButton}
>
<div className="spacer-md" />
{viewQR && this.renderQRView(sessionID)}
{viewDefault && this.renderDefaultView()}
{viewEdit && this.renderEditView()}
<div className="session-id-section">
<div className="panel-text-divider">
<span>{window.i18n('yourSessionID')}</span>
</div>
<p className="session-id-section-display">{sessionID}</p>
<div className="spacer-lg" />
{viewDefault || viewQR ? (
<SessionButton
text={window.i18n('copy')}
buttonType={SessionButtonType.BrandOutline}
buttonColor={SessionButtonColor.Green}
onClick={() => {
this.copySessionID(sessionID);
}}
/>
) : (
<SessionButton
text={window.i18n('save')}
buttonType={SessionButtonType.BrandOutline}
buttonColor={SessionButtonColor.White}
onClick={this.onClickOK}
/>
)}
<div className="spacer-lg" />
</div>
</SessionModal>
);
}
private renderProfileHeader() {
return (
<>
<div className="avatar-center">
<div className="avatar-center-inner">
{this.renderAvatar()}
<div className="image-upload-section">
<div
className="image-upload-section"
role="button"
onClick={() => {
const el = this.inputEl.current;
if (el) {
el.click();
}
}}
>
<input
type="file"
ref={this.inputEl}
@ -88,51 +154,80 @@ export class EditProfileDialog extends React.Component<Props, State> {
name="name"
onChange={this.onFileSelected}
/>
</div>
<div
className="qr-view-button"
role="button"
onClick={() => {
this.setState({ mode: 'qr' });
}}
>
<SessionIconButton
iconType={SessionIconType.Upload}
iconSize={SessionIconSize.Huge}
onClick={() => {
const el = this.inputEl.current;
if (el) {
el.click();
}
}}
iconType={SessionIconType.QR}
iconSize={SessionIconSize.Small}
iconColor={'#000000'}
/>
</div>
</div>
</div>
</>
);
}
<div className="spacer md" />
private renderDefaultView() {
return (
<>
{this.renderProfileHeader()}
<input
type="text"
className="profile-name"
value={this.state.profileName}
placeholder={placeholderText}
onChange={this.onNameEdited}
tabIndex={0}
required={true}
aria-required={true}
/>
<div className="message">{i18n('editProfileDisplayNameWarning')}</div>
<span className={errorMessageClasses}>{this.state.errorMessage}</span>
<div className="spacer-lg" />
<div className="session-modal__button-group">
<SessionButton
text={okText}
buttonColor={SessionButtonColor.Secondary}
onClick={this.onClickOK}
/>
<SessionButton
text={cancelText}
buttonColor={SessionButtonColor.Primary}
onClick={this.closeDialog}
<div className="profile-name-uneditable">
<p>{this.state.setProfileName}</p>
<SessionIconButton
iconType={SessionIconType.Pencil}
iconSize={SessionIconSize.Medium}
onClick={() => {
this.setState({ mode: 'edit' });
}}
/>
</div>
</SessionModal>
</>
);
}
private renderEditView() {
const placeholderText = window.i18n('displayName');
return (
<>
{this.renderProfileHeader()}
<div className="profile-name">
<input
type="text"
className="profile-name-input"
value={this.state.profileName}
placeholder={placeholderText}
onChange={this.onNameEdited}
tabIndex={0}
required={true}
aria-required={true}
/>
</div>
</>
);
}
private renderQRView(sessionID: string) {
const bgColor = '#FFFFFF';
const fgColor = '#1B1B1B';
return (
<div className="qr-image">
<QRCode
value={sessionID}
bgColor={bgColor}
fgColor={fgColor}
level="L"
/>
</div>
);
}
@ -189,29 +284,20 @@ export class EditProfileDialog extends React.Component<Props, State> {
}
}
private showError(msg: string) {
if (this.state.errorDisplayed) {
return;
}
private copySessionID(sessionID: string) {
window.clipboard.writeText(sessionID);
this.setState({
errorDisplayed: true,
errorMessage: msg,
window.pushToast({
title: window.i18n('copiedSessionID'),
type: 'success',
id: 'copiedSessionID',
});
setTimeout(() => {
this.setState({
errorDisplayed: false,
});
}, 3000);
}
private onClickOK() {
const newName = this.state.profileName.trim();
if (newName === '') {
this.showError(this.props.i18n('emptyProfileNameError'));
return;
}
@ -224,7 +310,11 @@ export class EditProfileDialog extends React.Component<Props, State> {
: null;
this.props.onOk(newName, avatar);
this.closeDialog();
this.setState({
mode: 'default',
setProfileName: this.state.profileName,
});
}
private closeDialog() {

View file

@ -25,7 +25,6 @@ interface State {
}
export class UserDetailsDialog extends React.Component<Props, State> {
constructor(props: any) {
super(props);

View file

@ -31,13 +31,12 @@ class Mention extends React.Component<MentionProps, MentionState> {
}
public componentWillMount() {
this.setState({ found: false });
// TODO: give up after some period of time?
this.intervalHandle = setInterval(this.tryRenameMention, 30000);
this.tryRenameMention();
this.tryRenameMention().ignore();
}
public componentWillUnmount() {

View file

@ -1089,7 +1089,7 @@ export class Message extends React.PureComponent<Props, State> {
const divClasses = ['loki-message-wrapper'];
if (shouldHightlight) {
divClasses.push('message-highlighted');
//divClasses.push('message-highlighted');
}
if (selected) {
divClasses.push('message-selected');

View file

@ -40,9 +40,10 @@ const Section = ({
}) => {
const handleClick = onSelect
? () => {
if (type !== SectionType.Profile) {
onSelect(type);
}
type === SectionType.Profile
? window.showEditProfileDialog()
: /* tslint:disable-next-line:no-void-expression */
onSelect(type);
}
: undefined;

View file

@ -170,9 +170,15 @@ export class LeftPaneChannelSection extends React.Component<Props, State> {
return LeftPane.RENDER_HEADER(labels, null);
}
public render(): JSX.Element {
public componentDidMount() {
MainViewController.renderMessageView();
}
public componentDidUpdate() {
MainViewController.renderMessageView();
}
public render(): JSX.Element {
return (
<div className="session-left-pane-section-content">
{this.renderHeader()}

View file

@ -94,9 +94,15 @@ export class LeftPaneContactSection extends React.Component<Props, State> {
);
}
public render(): JSX.Element {
public componentDidMount() {
MainViewController.renderMessageView();
}
public componentDidUpdate() {
MainViewController.renderMessageView();
}
public render(): JSX.Element {
return (
<div className="left-pane-contact-section">
{this.renderHeader()}

View file

@ -145,6 +145,14 @@ export class LeftPaneMessageSection extends React.Component<Props, any> {
return [list];
}
public componentDidMount() {
MainViewController.renderMessageView();
}
public componentDidUpdate() {
MainViewController.renderMessageView();
}
public renderHeader(): JSX.Element {
const labels = [window.i18n('messagesHeader')];
@ -157,8 +165,6 @@ export class LeftPaneMessageSection extends React.Component<Props, any> {
}
public render(): JSX.Element {
MainViewController.renderMessageView();
return (
<div className="session-left-pane-section-content">
{this.renderHeader()}

View file

@ -30,12 +30,17 @@ export class LeftPaneSettingSection extends React.Component<any, State> {
};
this.setCategory = this.setCategory.bind(this);
this.renderRows = this.renderRows.bind(this);
}
public componentDidMount() {
MainViewController.renderSettingsView(this.state.settingCategory);
}
public componentDidUpdate() {
MainViewController.renderSettingsView(this.state.settingCategory);
}
public render(): JSX.Element {
MainViewController.renderSettingsView(this.state.settingCategory);
return (
<div className="left-pane-setting-section">
{this.renderHeader()}
@ -56,53 +61,45 @@ export class LeftPaneSettingSection extends React.Component<any, State> {
);
}
public renderRows(): JSX.Element {
const categories = this.getCategories();
public renderRow(item: any): JSX.Element {
return (
<>
{categories.map(item => (
<>
{!item.hidden && (
<div
key={item.id}
className={classNames(
'left-pane-setting-category-list-item',
item.id === this.state.settingCategory ? 'active' : ''
)}
role="link"
onClick={() => {
this.setCategory(item.id);
}}
>
<div>
<strong>{item.title}</strong>
<br />
<span className="text-subtle">{item.description}</span>
</div>
<div
key={item.id}
className={classNames(
'left-pane-setting-category-list-item',
item.id === this.state.settingCategory ? 'active' : ''
)}
role="link"
onClick={() => {
this.setCategory(item.id);
}}
>
<div>
<strong>{item.title}</strong>
<br />
<span className="text-subtle">{item.description}</span>
</div>
<div>
{item.id === this.state.settingCategory && (
<SessionIcon
iconSize={SessionIconSize.Medium}
iconType={SessionIconType.Chevron}
iconRotation={270}
/>
)}
</div>
</div>
)}
</>
))}
</>
<div>
{item.id === this.state.settingCategory && (
<SessionIcon
iconSize={SessionIconSize.Medium}
iconType={SessionIconType.Chevron}
iconRotation={270}
/>
)}
</div>
</div>
);
}
public renderCategories(): JSX.Element {
const categories = this.getCategories().filter(item => !item.hidden);
return (
<div className="module-left-pane__list" key={0}>
<div className="left-pane-setting-category-list">
{this.renderRows()}
{categories.map(item => this.renderRow(item))};
</div>
</div>
);

View file

@ -1,6 +1,8 @@
import React from 'react';
import classNames from 'classnames';
import { SessionIconButton, SessionIconSize, SessionIconType } from './icon/';
import { SessionButtonColor, SessionButtonType } from './SessionButton';
interface Props {
title: string;
@ -8,9 +10,17 @@ interface Props {
onOk: any;
showExitIcon?: boolean;
showHeader?: boolean;
//Maximum of two icons in header
headerReverse?: boolean;
//Maximum of two icons or buttons in header
headerIconButtons?: Array<{
type: SessionIconType;
iconType: SessionIconType;
iconRotation: number;
onClick?: any;
}>;
headerButtons?: Array<{
buttonType: SessionButtonType;
buttonColor: SessionButtonColor;
text: string;
onClick?: any;
}>;
}
@ -23,6 +33,7 @@ export class SessionModal extends React.PureComponent<Props, State> {
public static defaultProps = {
showExitIcon: true,
showHeader: true,
headerReverse: false,
};
constructor(props: any) {
@ -38,14 +49,25 @@ export class SessionModal extends React.PureComponent<Props, State> {
}
public render() {
const { title, headerIconButtons, showExitIcon, showHeader } = this.props;
const {
title,
headerIconButtons,
showExitIcon,
showHeader,
headerReverse,
} = this.props;
const { isVisible } = this.state;
return isVisible ? (
<div className={'session-modal'}>
{showHeader ? (
<>
<div className="session-modal__header">
<div
className={classNames(
'session-modal__header',
headerReverse && 'reverse'
)}
>
<div className="session-modal__header__close">
{showExitIcon ? (
<SessionIconButton
@ -61,9 +83,11 @@ export class SessionModal extends React.PureComponent<Props, State> {
? headerIconButtons.map((iconItem: any) => {
return (
<SessionIconButton
key={iconItem.type}
iconType={iconItem.type}
iconSize={SessionIconSize.Medium}
key={iconItem.iconType}
iconType={iconItem.iconType}
iconSize={SessionIconSize.Large}
iconRotation={iconItem.iconRotation}
onClick={iconItem.onClick}
/>
);
})

View file

@ -17,11 +17,9 @@ export class SessionQRModal extends React.Component<Props> {
public render() {
const { value, onClose } = this.props;
const theme = window.Events.getThemeSetting();
// Foreground equivalent to .session-modal background color
const bgColor = 'rgba(0, 0, 0, 0)';
const fgColor = theme === 'dark' ? '#FFFFFF' : '#1B1B1B';
const bgColor = '#FFFFFF';
const fgColor = '#1B1B1B';
return (
<SessionModal

View file

@ -22,6 +22,7 @@ export enum SessionIconType {
Lock = 'lock',
Microphone = 'microphone',
Moon = 'moon',
Pencil = 'pencil',
Reply = 'reply',
Search = 'search',
Send = 'send',
@ -154,6 +155,11 @@ export const icons = {
'M11.1441877,12.8180303 C8.90278993,10.5766325 8.24397847,7.29260898 9.27752593,4.437982 C6.09633644,5.5873034 3.89540402,8.67837285 4.00385273,12.2078365 C4.13368986,16.4333868 7.52883112,19.8285281 11.7543814,19.9583652 C15.2838451,20.0668139 18.3749145,17.8658815 19.5242359,14.684692 C16.669609,15.7182395 13.3855854,15.059428 11.1441877,12.8180303 Z M21.9576498,12.8823459 C21.4713729,18.1443552 16.9748949,22.1197182 11.692957,21.9574217 C6.41101918,21.7951253 2.16709261,17.5511988 2.00479619,12.2692609 C1.84249977,6.98732307 5.81786273,2.49084501 11.0798721,2.00456809 C11.9400195,1.92507947 12.4895134,2.90008536 11.9760569,3.59473245 C10.2106529,5.98311963 10.4582768,9.30369233 12.5584012,11.4038167 C14.6585256,13.5039411 17.9790983,13.7515651 20.3674855,11.986161 C21.0621326,11.4727046 22.0371385,12.0221984 21.9576498,12.8823459 lZ',
viewBox: '0.5 0.5 22 22',
},
[SessionIconType.Pencil]: {
path:
'M4,16.4142136 L4,20 L7.58578644,20 L19.5857864,8 L16,4.41421356 L4,16.4142136 Z M16.7071068,2.29289322 L21.7071068,7.29289322 C22.0976311,7.68341751 22.0976311,8.31658249 21.7071068,8.70710678 L8.70710678,21.7071068 C8.5195704,21.8946432 8.26521649,22 8,22 L3,22 C2.44771525,22 2,21.5522847 2,21 L2,16 C2,15.7347835 2.10535684,15.4804296 2.29289322,15.2928932 L15.2928932,2.29289322 C15.6834175,1.90236893 16.3165825,1.90236893 16.7071068,2.29289322 Z',
viewBox: '1 1 21 21',
},
[SessionIconType.Reply]: {
path:
'M4,3 C4.55228475,3 5,3.44771525 5,4 L5,4 L5,11 C5,12.6568542 6.34314575,14 8,14 L8,14 L17.585,14 L14.2928932,10.7071068 C13.9324093,10.3466228 13.9046797,9.77939176 14.2097046,9.38710056 L14.2928932,9.29289322 C14.6834175,8.90236893 15.3165825,8.90236893 15.7071068,9.29289322 L15.7071068,9.29289322 L20.7071068,14.2928932 C20.7355731,14.3213595 20.7623312,14.3515341 20.787214,14.3832499 C20.788658,14.3849951 20.7902348,14.3870172 20.7918027,14.389044 C20.8140715,14.4179625 20.8348358,14.4480862 20.8539326,14.4793398 C20.8613931,14.4913869 20.8685012,14.5036056 20.8753288,14.5159379 C20.8862061,14.5357061 20.8966234,14.5561086 20.9063462,14.5769009 C20.914321,14.5939015 20.9218036,14.6112044 20.9287745,14.628664 C20.9366843,14.6484208 20.9438775,14.6682023 20.9504533,14.6882636 C20.9552713,14.7031487 20.9599023,14.7185367 20.9641549,14.734007 C20.9701664,14.7555635 20.9753602,14.7772539 20.9798348,14.7992059 C20.9832978,14.8166247 20.9863719,14.834051 20.9889822,14.8515331 C20.9962388,14.8996379 21,14.9493797 21,15 L20.9962979,14.9137692 C20.9978436,14.9317345 20.9989053,14.9497336 20.9994829,14.9677454 L21,15 C21,15.0112225 20.9998151,15.0224019 20.9994483,15.0335352 C20.9988772,15.050591 20.997855,15.0679231 20.996384,15.0852242 C20.994564,15.1070574 20.9920941,15.1281144 20.9889807,15.1489612 C20.9863719,15.165949 20.9832978,15.1833753 20.9797599,15.2007258 C20.9753602,15.2227461 20.9701664,15.2444365 20.964279,15.2658396 C20.9599023,15.2814633 20.9552713,15.2968513 20.9502619,15.3121425 C20.9438775,15.3317977 20.9366843,15.3515792 20.928896,15.3710585 C20.9218036,15.3887956 20.914321,15.4060985 20.9063266,15.4232215 C20.8974314,15.4421635 20.8879327,15.4609002 20.8778732,15.4792864 C20.8703855,15.4931447 20.862375,15.5070057 20.8540045,15.5207088 C20.8382813,15.546275 20.8215099,15.5711307 20.8036865,15.5951593 C20.774687,15.6343256 20.7425008,15.6717127 20.7071068,15.7071068 L20.787214,15.6167501 C20.7849289,15.6196628 20.7826279,15.6225624 20.7803112,15.625449 L20.7071068,15.7071068 L15.7071068,20.7071068 C15.3165825,21.0976311 14.6834175,21.0976311 14.2928932,20.7071068 C13.9023689,20.3165825 13.9023689,19.6834175 14.2928932,19.2928932 L14.2928932,19.2928932 L17.585,16 L8,16 C5.3112453,16 3.11818189,13.8776933 3.00461951,11.2168896 L3,11 L3,4 C3,3.44771525 3.44771525,3 4,3 lZ',

View file

@ -156,15 +156,15 @@ export class SettingsView extends React.Component<SettingsViewProps, State> {
defaultValue=""
placeholder={' '}
/>
<div className="spacer-sm" />
<div className="spacer-xs" />
{this.state.pwdLockError && (
<>
<div className="session-label warning">
{this.state.pwdLockError}
</div>
<div className="spacer-sm" />
<div className="spacer-lg" />
</>
)}
@ -186,7 +186,7 @@ export class SettingsView extends React.Component<SettingsViewProps, State> {
this.setState({
pwdLockError: window.i18n('noGivenPassword'),
});
return false;
}
@ -216,7 +216,10 @@ export class SettingsView extends React.Component<SettingsViewProps, State> {
return (
<div className="session-settings">
<SettingsHeader category={category} />
<SettingsHeader
showLinkDeviceButton={!shouldRenderPasswordLock}
category={category}
/>
{shouldRenderPasswordLock ? (
this.renderPasswordLock()
) : (
@ -294,7 +297,7 @@ export class SettingsView extends React.Component<SettingsViewProps, State> {
{
id: 'theme-setting',
title: window.i18n('themeToggleTitle'),
description: 'Choose the theme best suited to you',
description: window.i18n('themeToggleDescription'),
hidden: true,
comparisonValue: 'light',
type: SessionSettingType.Toggle,
@ -311,7 +314,7 @@ export class SettingsView extends React.Component<SettingsViewProps, State> {
type: SessionSettingType.Toggle,
category: SessionSettingCategory.General,
setFn: window.toggleMenuBar,
content: undefined,
content: { defaultValue: true },
comparisonValue: undefined,
onClick: undefined,
},

View file

@ -4,11 +4,21 @@ import { SessionIconButton, SessionIconSize, SessionIconType } from '../icon';
import { SessionSettingCategory, SettingsViewProps } from './SessionSettings';
import { SessionButton } from '../SessionButton';
export class SettingsHeader extends React.Component<SettingsViewProps, any> {
interface Props extends SettingsViewProps {
showLinkDeviceButton: boolean | null;
disableLinkDeviceButton: boolean | null;
}
export class SettingsHeader extends React.Component<Props, any> {
public static defaultProps = {
showLinkDeviceButton: false,
disableLinkDeviceButton: true,
};
public constructor(props: any) {
super(props);
this.state = {
disableLinkDeviceButton: true,
disableLinkDeviceButton: this.props.disableLinkDeviceButton,
};
this.showAddLinkedDeviceModal = this.showAddLinkedDeviceModal.bind(this);
}
@ -56,7 +66,9 @@ export class SettingsHeader extends React.Component<SettingsViewProps, any> {
? `${categoryTitlePrefix.slice(0, -1)} Settings`
: `${categoryTitlePrefix} Settings`;
const showSearch = false;
const showAddDevice = category === SessionSettingCategory.Devices;
const showAddDevice =
category === SessionSettingCategory.Devices &&
this.props.showLinkDeviceButton;
return (
<div className="session-settings-header">

2
ts/global.d.ts vendored
View file

@ -28,8 +28,10 @@ interface Window {
pushToast: any;
confirmationDialog: any;
showQRDialog: any;
showSeedDialog: any;
showPasswordDialog: any;
showEditProfileDialog: any;
deleteAccount: any;

View file

@ -2265,6 +2265,13 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
cross-env@^6.0.3:
version "6.0.3"
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-6.0.3.tgz#4256b71e49b3a40637a0ce70768a6ef5c72ae941"
integrity sha512-+KqxF6LCvfhWvADcDPqo64yVIB31gv/jQulX2NGzKS/g3GEVz6/pt4wjHFtFWsHMddebWD/sDthJemzM4MaAag==
dependencies:
cross-spawn "^7.0.0"
cross-spawn@5.1.0, cross-spawn@^5.0.1, cross-spawn@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
@ -2290,6 +2297,15 @@ cross-spawn@^4:
lru-cache "^4.0.1"
which "^1.2.9"
cross-spawn@^7.0.0:
version "7.0.1"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14"
integrity sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==
dependencies:
path-key "^3.1.0"
shebang-command "^2.0.0"
which "^2.0.1"
crypto-browserify@^3.11.0:
version "3.12.0"
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
@ -7334,6 +7350,11 @@ path-key@^2.0.0:
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
path-key@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
path-parse@^1.0.5, path-parse@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
@ -9249,11 +9270,23 @@ shebang-command@^1.2.0:
dependencies:
shebang-regex "^1.0.0"
shebang-command@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
dependencies:
shebang-regex "^3.0.0"
shebang-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
shebang-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
shell-quote@1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767"
@ -10937,6 +10970,13 @@ which@1, which@^1.2.10, which@^1.2.14, which@^1.2.9, which@^1.3.0:
dependencies:
isexe "^2.0.0"
which@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
dependencies:
isexe "^2.0.0"
which@~1.2.1:
version "1.2.14"
resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5"