diff --git a/Gruntfile.js b/Gruntfile.js index 6a243b2b4..623b6c8ad 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -9,6 +9,7 @@ const toConcatForApp = [ 'node_modules/long/dist/long.js', 'components/protobuf/**/*.js', 'node_modules/mustache/mustache.js', + 'node_modules/underscore/underscore-min.js', 'node_modules/backbone/backbone.js', ]; diff --git a/_locales/en/messages.json b/_locales/en/messages.json index c0ab18058..a1deaa5ba 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -335,8 +335,8 @@ "onlyAdminCanRemoveMembersDesc": "Only the creator of the group can remove users", "createAccount": "Create account", "signIn": "Sign In", - "startInTrayTitle": "Start in Tray", - "startInTrayDescription": "Start Session as a minified app ", + "startInTrayTitle": "Keep in System Tray", + "startInTrayDescription": "Session continues running in the background when you close the window", "yourUniqueSessionID": "Say hello to your Session ID", "allUsersAreRandomly...": "Your Session ID is the unique address people can use to contact you on Session. With no connection to your real identity, your Session ID is totally anonymous and private by design.", "getStarted": "Get started", diff --git a/app/sql.js b/app/sql.js index 2d9438c13..1e84d5424 100644 --- a/app/sql.js +++ b/app/sql.js @@ -842,6 +842,7 @@ const LOKI_SCHEMA_VERSIONS = [ updateToLokiSchemaVersion17, updateToLokiSchemaVersion18, updateToLokiSchemaVersion19, + updateToLokiSchemaVersion20, ]; function updateToLokiSchemaVersion1(currentVersion, db) { @@ -1337,6 +1338,43 @@ function updateToLokiSchemaVersion19(currentVersion, db) { console.log(`updateToLokiSchemaVersion${targetVersion}: success!`); } +function updateToLokiSchemaVersion20(currentVersion, db) { + const targetVersion = 20; + if (currentVersion >= targetVersion) { + return; + } + + console.log(`updateToLokiSchemaVersion${targetVersion}: starting...`); + db.transaction(() => { + // looking for all private conversations, with a nickname set + const rowsToUpdate = db + .prepare( + `SELECT * FROM ${CONVERSATIONS_TABLE} WHERE type = 'private' AND (name IS NULL or name = '') AND json_extract(json, '$.nickname') <> '';` + ) + .all(); + (rowsToUpdate || []).forEach(r => { + const obj = jsonToObject(r.json); + + // obj.profile.displayName is the display as this user set it. + if ( + obj && + obj.nickname && + obj.nickname.length && + obj.profile && + obj.profile.displayName && + obj.profile.displayName.length + ) { + // this one has a nickname set, but name is unset, set it to the displayName in the lokiProfile if it's exisitng + obj.name = obj.profile.displayName; + updateConversation(obj, db); + } + }); + + writeLokiSchemaVersion(targetVersion, db); + })(); + console.log(`updateToLokiSchemaVersion${targetVersion}: success!`); +} + function writeLokiSchemaVersion(newVersion, db) { db.prepare( `INSERT INTO loki_schema( @@ -1665,10 +1703,10 @@ function getConversationCount() { return row['count(*)']; } -function saveConversation(data) { +function saveConversation(data, instance) { const { id, active_at, type, members, name, profileName } = data; - globalInstance + (globalInstance || instance) .prepare( `INSERT INTO ${CONVERSATIONS_TABLE} ( id, @@ -1702,7 +1740,7 @@ function saveConversation(data) { }); } -function updateConversation(data) { +function updateConversation(data, instance) { const { id, // eslint-disable-next-line camelcase @@ -1713,7 +1751,8 @@ function updateConversation(data) { profileName, } = data; - globalInstance + (globalInstance || instance) + .prepare( `UPDATE ${CONVERSATIONS_TABLE} SET json = $json, diff --git a/fonts/Roboto-Light.ttf b/fonts/Roboto-Light.ttf deleted file mode 100644 index 0e977514f..000000000 Binary files a/fonts/Roboto-Light.ttf and /dev/null differ diff --git a/fonts/Roboto-LightItalic.ttf b/fonts/Roboto-LightItalic.ttf deleted file mode 100644 index 3ad14fa7c..000000000 Binary files a/fonts/Roboto-LightItalic.ttf and /dev/null differ diff --git a/package.json b/package.json index 66f297b60..29a31bd85 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,6 @@ "p-retry": "^4.2.0", "pify": "3.0.0", "protobufjs": "^6.11.2", - "rc-slider": "^8.7.1", "react": "^17.0.2", "react-contexify": "5.0.0", diff --git a/stylesheets/_modules.scss b/stylesheets/_modules.scss index 99345556b..52f1e3560 100644 --- a/stylesheets/_modules.scss +++ b/stylesheets/_modules.scss @@ -6,17 +6,7 @@ flex-direction: column; align-items: flex-start; overflow-x: hidden; -} - -.create-group-button { - background-color: #383c46; - color: #ffffff; - margin: 4px; - padding: 4px; -} - -.create-group-button:focus { - outline: 0; + font-weight: 400; } .module-contact-name span { @@ -348,7 +338,7 @@ min-width: 0; font-size: 16px; line-height: 24px; - font-weight: 300; + font-weight: 400; color: var(--color-text); // width of avatar (28px) and our 6px left margin diff --git a/stylesheets/_session.scss b/stylesheets/_session.scss index e6cf61bfc..e89ee0a22 100644 --- a/stylesheets/_session.scss +++ b/stylesheets/_session.scss @@ -277,7 +277,7 @@ textarea { &-text { @include session-color-subtle(var(--color-text)); - font-weight: 300; + font-weight: 400; font-size: $session-font-sm; line-height: $session-font-sm; } diff --git a/stylesheets/_session_constants.scss b/stylesheets/_session_constants.scss index c9c4f479a..77fc41039 100644 --- a/stylesheets/_session_constants.scss +++ b/stylesheets/_session_constants.scss @@ -10,32 +10,18 @@ $session-font-mono: 'SpaceMono'; font-family: $session-font-mono; src: url('../fonts/SpaceMono-Regular.ttf') format('truetype'); } -@font-face { - font-family: $session-font-mono; - src: url('../fonts/SpaceMono-Bold.ttf') format('truetype'); - font-weight: bold; -} -@font-face { - font-family: $session-font-mono; - src: url('../fonts/SpaceMono-Italic.ttf') format('truetype'); - font-style: italic; -} -@font-face { - font-family: $session-font-mono; - src: url('../fonts/SpaceMono-BoldItalic.ttf') format('truetype'); - font-weight: bold; - font-style: italic; -} // Roboto is an open replacement for $session-font-default @font-face { font-family: $session-font-default; src: url('../fonts/Roboto-Regular.ttf') format('truetype'); + font-weight: 300; } @font-face { font-family: $session-font-default; src: url('../fonts/Roboto-Italic.ttf') format('truetype'); font-style: italic; + font-weight: 300; } @font-face { font-family: $session-font-default; @@ -48,17 +34,6 @@ $session-font-mono: 'SpaceMono'; font-weight: 600; font-style: italic; } -@font-face { - font-family: $session-font-default; - src: url('../fonts/Roboto-Light.ttf') format('truetype'); - font-weight: 200; -} -@font-face { - font-family: $session-font-default; - src: url('../fonts/Roboto-LightItalic.ttf') format('truetype'); - font-weight: 200; - font-style: italic; -} // Accented font @font-face { diff --git a/ts/components/conversation/ContactName.tsx b/ts/components/conversation/ContactName.tsx index 0994336dc..43b8868ba 100644 --- a/ts/components/conversation/ContactName.tsx +++ b/ts/components/conversation/ContactName.tsx @@ -2,7 +2,7 @@ import React from 'react'; import classNames from 'classnames'; import { Emojify } from './Emojify'; -import { useConversationUsername } from '../../hooks/useParamSelector'; +import { useConversationUsernameOrShorten } from '../../hooks/useParamSelector'; type Props = { pubkey: string; @@ -18,7 +18,7 @@ export const ContactName = (props: Props) => { const { pubkey, name, profileName, module, boldProfileName, compact, shouldShowPubkey } = props; const prefix = module ? module : 'module-contact-name'; - const convoName = useConversationUsername(pubkey); + const convoName = useConversationUsernameOrShorten(pubkey); const shouldShowProfile = Boolean(convoName || profileName || name); const styles = (boldProfileName diff --git a/ts/components/leftpane/conversation-list-item/UserItem.tsx b/ts/components/leftpane/conversation-list-item/UserItem.tsx index a550ac534..22ee22564 100644 --- a/ts/components/leftpane/conversation-list-item/UserItem.tsx +++ b/ts/components/leftpane/conversation-list-item/UserItem.tsx @@ -26,7 +26,7 @@ export const UserItem = () => { const displayedPubkey = username ? shortenedPubkey : conversationId; const displayName = isMe ? window.i18n('noteToSelf') - : isSearchResultsMode && hasNickname + : isSearchResultsMode && hasNickname && realName ? `${realName} (${username})` : username; diff --git a/ts/components/search/MessageSearchResults.tsx b/ts/components/search/MessageSearchResults.tsx index 98ca54cc9..926dbf32b 100644 --- a/ts/components/search/MessageSearchResults.tsx +++ b/ts/components/search/MessageSearchResults.tsx @@ -101,7 +101,7 @@ const ConversationHeader = (props: { source: string; conversationId: string }) = return ( - + ); @@ -109,7 +109,7 @@ const ConversationHeader = (props: { source: string; conversationId: string }) = return ( - ; + ); }; @@ -203,6 +203,7 @@ export const MessageSearchResult = (props: MessageResultProps) => { if (!source && !destination) { return null; } + // tslint:disable: use-simple-attributes return ( { {noResults ? {window.i18n('noSearchResults', [searchTerm])} : null} {haveContactsAndGroup ? ( -
+ <> {window.i18n('conversationsHeader')} {contactsAndGroups.map(contactOrGroup => ( { key={`search-result-convo-${contactOrGroup.id}`} /> ))} -
+ ) : null} {haveMessages && ( -
+ <> {`${window.i18n('messagesHeader')}: ${messages.length}`} {messages.map(message => ( ))} -
+ )}
); diff --git a/ts/hooks/useParamSelector.ts b/ts/hooks/useParamSelector.ts index e36f4a2c6..3cff7c8a4 100644 --- a/ts/hooks/useParamSelector.ts +++ b/ts/hooks/useParamSelector.ts @@ -32,11 +32,11 @@ export function useConversationUsernameOrShorten(convoId?: string) { } /** - * Returns either the nickname, profileName, or the shorten pubkey + * Returns the name if that conversation. + * This is the group name, or the realName of a user for a private conversation with a recent nickname set */ export function useConversationRealName(convoId?: string) { const convoProps = useConversationPropsById(convoId); - return convoProps?.isPrivate ? convoProps?.name : undefined; } diff --git a/ts/models/conversation.ts b/ts/models/conversation.ts index 0ad2939d2..5dfa64440 100644 --- a/ts/models/conversation.ts +++ b/ts/models/conversation.ts @@ -1094,29 +1094,7 @@ export class ConversationModel extends Backbone.Model { const groupAdmins = this.getGroupAdmins(); return Array.isArray(groupAdmins) && groupAdmins.includes(pubKey); } - // SIGNAL PROFILES - public async getProfiles() { - // request all conversation members' keys - let ids = []; - if (this.isPrivate()) { - ids = [this.id]; - } else { - ids = this.get('members'); - } - return Promise.all(_.map(ids, this.getProfile)); - } - // This function is wrongly named by signal - // This is basically an `update` function and thus we have overwritten it with such - public async getProfile(id: string) { - const c = await getConversationController().getOrCreateAndWait( - id, - ConversationTypeEnum.PRIVATE - ); - - // We only need to update the profile as they are all stored inside the conversation - await c.updateProfileName(); - } public async setProfileName(name: string) { const profileName = this.get('profileName'); if (profileName !== name) { diff --git a/ts/receiver/closedGroups.ts b/ts/receiver/closedGroups.ts index ab5fa3591..8dc33d3b2 100644 --- a/ts/receiver/closedGroups.ts +++ b/ts/receiver/closedGroups.ts @@ -285,7 +285,7 @@ export async function handleNewClosedGroup( await ClosedGroup.addUpdateMessage( convo, { newName: name, joiningMembers: members }, - 'incoming', + envelope.senderIdentity || envelope.source, // new group message are coming as session messages envelopeTimestamp ); @@ -560,7 +560,7 @@ async function handleClosedGroupNameChanged( await ClosedGroup.addUpdateMessage( convo, groupDiff, - 'incoming', + envelope.senderIdentity, _.toNumber(envelope.timestamp) ); convo.set({ name: newName }); @@ -613,7 +613,12 @@ async function handleClosedGroupMembersAdded( const groupDiff: ClosedGroup.GroupDiff = { joiningMembers: membersNotAlreadyPresent, }; - await ClosedGroup.addUpdateMessage(convo, groupDiff, 'incoming', _.toNumber(envelope.timestamp)); + await ClosedGroup.addUpdateMessage( + convo, + groupDiff, + envelope.senderIdentity, + _.toNumber(envelope.timestamp) + ); convo.set({ members }); @@ -686,7 +691,7 @@ async function handleClosedGroupMembersRemoved( await ClosedGroup.addUpdateMessage( convo, groupDiff, - 'incoming', + envelope.senderIdentity, _.toNumber(envelope.timestamp) ); convo.updateLastMessage(); @@ -763,7 +768,12 @@ async function handleClosedGroupAdminMemberLeft( }; convo.set('members', []); - await ClosedGroup.addUpdateMessage(convo, groupDiff, 'incoming', _.toNumber(envelope.timestamp)); + await ClosedGroup.addUpdateMessage( + convo, + groupDiff, + envelope.senderIdentity, + _.toNumber(envelope.timestamp) + ); convo.updateLastMessage(); await convo.commit(); @@ -779,7 +789,12 @@ async function handleClosedGroupLeftOurself( const groupDiff: ClosedGroup.GroupDiff = { leavingMembers: [envelope.senderIdentity], }; - await ClosedGroup.addUpdateMessage(convo, groupDiff, 'incoming', _.toNumber(envelope.timestamp)); + await ClosedGroup.addUpdateMessage( + convo, + groupDiff, + envelope.senderIdentity, + _.toNumber(envelope.timestamp) + ); convo.updateLastMessage(); // remove ourself from the list of members convo.set( @@ -828,7 +843,12 @@ async function handleClosedGroupMemberLeft(envelope: EnvelopePlus, convo: Conver leavingMembers: [sender], }; - await ClosedGroup.addUpdateMessage(convo, groupDiff, 'incoming', _.toNumber(envelope.timestamp)); + await ClosedGroup.addUpdateMessage( + convo, + groupDiff, + envelope.senderIdentity, + _.toNumber(envelope.timestamp) + ); convo.updateLastMessage(); // if a user just left and we are the admin, we remove him right away for everyone by sending a MEMBERS_REMOVED message so no need to add him as a zombie if (oldMembers.includes(sender)) { @@ -918,7 +938,12 @@ export async function createClosedGroup(groupName: string, members: Array { const groupUpdate: any = {}; @@ -156,25 +170,28 @@ export async function addUpdateMessage( groupUpdate.kicked = diff.kickedMembers; } - const unread = type === 'incoming'; - - const message = await convo.addSingleOutgoingMessage({ + if (UserUtils.isUsFromCache(sender)) { + const outgoingMessage = await convo.addSingleOutgoingMessage({ + sent_at: sentAt, + group_update: groupUpdate, + unread: 1, + expireTimer: 0, + }); + return outgoingMessage; + } + const incomingMessage = await convo.addSingleIncomingMessage({ sent_at: sentAt, group_update: groupUpdate, - unread: unread ? 1 : 0, expireTimer: 0, + source: sender, }); - - if (unread) { - // update the unreadCount for this convo - const unreadCount = await convo.getUnreadCount(); - convo.set({ - unreadCount, - }); - await convo.commit(); - } - - return message; + // update the unreadCount for this convo + const unreadCount = await convo.getUnreadCount(); + convo.set({ + unreadCount, + }); + await convo.commit(); + return incomingMessage; } function buildGroupDiff(convo: ConversationModel, update: GroupInfo): GroupDiff { @@ -326,7 +343,7 @@ async function sendNewName(convo: ConversationModel, name: string, messageId: st // Send the update to the group const nameChangeMessage = new ClosedGroupNameChangeMessage({ timestamp: Date.now(), - groupId: groupId as string, + groupId, identifier: messageId, name, }); @@ -396,7 +413,7 @@ export async function sendRemovedMembers( } const ourNumber = UserUtils.getOurPubKeyFromCache(); const admins = convo.get('groupAdmins') || []; - const groupId = convo.get('id') as string; + const groupId = convo.get('id'); const isCurrentUserAdmin = admins.includes(ourNumber.key); const isUserLeaving = removedMembers.includes(ourNumber.key);