Merge pull request #2154 from Bilb/update-wording-systray

update EN start in tray setting wording
pull/2158/head
Audric Ackermann 3 years ago committed by GitHub
commit 1b98456e29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -9,6 +9,7 @@ const toConcatForApp = [
'node_modules/long/dist/long.js', 'node_modules/long/dist/long.js',
'components/protobuf/**/*.js', 'components/protobuf/**/*.js',
'node_modules/mustache/mustache.js', 'node_modules/mustache/mustache.js',
'node_modules/underscore/underscore-min.js',
'node_modules/backbone/backbone.js', 'node_modules/backbone/backbone.js',
]; ];

@ -335,8 +335,8 @@
"onlyAdminCanRemoveMembersDesc": "Only the creator of the group can remove users", "onlyAdminCanRemoveMembersDesc": "Only the creator of the group can remove users",
"createAccount": "Create account", "createAccount": "Create account",
"signIn": "Sign In", "signIn": "Sign In",
"startInTrayTitle": "Start in Tray", "startInTrayTitle": "Keep in System Tray",
"startInTrayDescription": "Start Session as a minified app ", "startInTrayDescription": "Session continues running in the background when you close the window",
"yourUniqueSessionID": "Say hello to your Session ID", "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.", "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", "getStarted": "Get started",

@ -842,6 +842,7 @@ const LOKI_SCHEMA_VERSIONS = [
updateToLokiSchemaVersion17, updateToLokiSchemaVersion17,
updateToLokiSchemaVersion18, updateToLokiSchemaVersion18,
updateToLokiSchemaVersion19, updateToLokiSchemaVersion19,
updateToLokiSchemaVersion20,
]; ];
function updateToLokiSchemaVersion1(currentVersion, db) { function updateToLokiSchemaVersion1(currentVersion, db) {
@ -1337,6 +1338,43 @@ function updateToLokiSchemaVersion19(currentVersion, db) {
console.log(`updateToLokiSchemaVersion${targetVersion}: success!`); 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) { function writeLokiSchemaVersion(newVersion, db) {
db.prepare( db.prepare(
`INSERT INTO loki_schema( `INSERT INTO loki_schema(
@ -1665,10 +1703,10 @@ function getConversationCount() {
return row['count(*)']; return row['count(*)'];
} }
function saveConversation(data) { function saveConversation(data, instance) {
const { id, active_at, type, members, name, profileName } = data; const { id, active_at, type, members, name, profileName } = data;
globalInstance (globalInstance || instance)
.prepare( .prepare(
`INSERT INTO ${CONVERSATIONS_TABLE} ( `INSERT INTO ${CONVERSATIONS_TABLE} (
id, id,
@ -1702,7 +1740,7 @@ function saveConversation(data) {
}); });
} }
function updateConversation(data) { function updateConversation(data, instance) {
const { const {
id, id,
// eslint-disable-next-line camelcase // eslint-disable-next-line camelcase
@ -1713,7 +1751,8 @@ function updateConversation(data) {
profileName, profileName,
} = data; } = data;
globalInstance (globalInstance || instance)
.prepare( .prepare(
`UPDATE ${CONVERSATIONS_TABLE} SET `UPDATE ${CONVERSATIONS_TABLE} SET
json = $json, json = $json,

Binary file not shown.

Binary file not shown.

@ -95,7 +95,6 @@
"p-retry": "^4.2.0", "p-retry": "^4.2.0",
"pify": "3.0.0", "pify": "3.0.0",
"protobufjs": "^6.11.2", "protobufjs": "^6.11.2",
"rc-slider": "^8.7.1", "rc-slider": "^8.7.1",
"react": "^17.0.2", "react": "^17.0.2",
"react-contexify": "5.0.0", "react-contexify": "5.0.0",

@ -6,17 +6,7 @@
flex-direction: column; flex-direction: column;
align-items: flex-start; align-items: flex-start;
overflow-x: hidden; overflow-x: hidden;
} font-weight: 400;
.create-group-button {
background-color: #383c46;
color: #ffffff;
margin: 4px;
padding: 4px;
}
.create-group-button:focus {
outline: 0;
} }
.module-contact-name span { .module-contact-name span {
@ -348,7 +338,7 @@
min-width: 0; min-width: 0;
font-size: 16px; font-size: 16px;
line-height: 24px; line-height: 24px;
font-weight: 300; font-weight: 400;
color: var(--color-text); color: var(--color-text);
// width of avatar (28px) and our 6px left margin // width of avatar (28px) and our 6px left margin

@ -277,7 +277,7 @@ textarea {
&-text { &-text {
@include session-color-subtle(var(--color-text)); @include session-color-subtle(var(--color-text));
font-weight: 300; font-weight: 400;
font-size: $session-font-sm; font-size: $session-font-sm;
line-height: $session-font-sm; line-height: $session-font-sm;
} }

@ -10,32 +10,18 @@ $session-font-mono: 'SpaceMono';
font-family: $session-font-mono; font-family: $session-font-mono;
src: url('../fonts/SpaceMono-Regular.ttf') format('truetype'); 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 // Roboto is an open replacement for $session-font-default
@font-face { @font-face {
font-family: $session-font-default; font-family: $session-font-default;
src: url('../fonts/Roboto-Regular.ttf') format('truetype'); src: url('../fonts/Roboto-Regular.ttf') format('truetype');
font-weight: 300;
} }
@font-face { @font-face {
font-family: $session-font-default; font-family: $session-font-default;
src: url('../fonts/Roboto-Italic.ttf') format('truetype'); src: url('../fonts/Roboto-Italic.ttf') format('truetype');
font-style: italic; font-style: italic;
font-weight: 300;
} }
@font-face { @font-face {
font-family: $session-font-default; font-family: $session-font-default;
@ -48,17 +34,6 @@ $session-font-mono: 'SpaceMono';
font-weight: 600; font-weight: 600;
font-style: italic; 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 // Accented font
@font-face { @font-face {

@ -2,7 +2,7 @@ import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { Emojify } from './Emojify'; import { Emojify } from './Emojify';
import { useConversationUsername } from '../../hooks/useParamSelector'; import { useConversationUsernameOrShorten } from '../../hooks/useParamSelector';
type Props = { type Props = {
pubkey: string; pubkey: string;
@ -18,7 +18,7 @@ export const ContactName = (props: Props) => {
const { pubkey, name, profileName, module, boldProfileName, compact, shouldShowPubkey } = props; const { pubkey, name, profileName, module, boldProfileName, compact, shouldShowPubkey } = props;
const prefix = module ? module : 'module-contact-name'; const prefix = module ? module : 'module-contact-name';
const convoName = useConversationUsername(pubkey); const convoName = useConversationUsernameOrShorten(pubkey);
const shouldShowProfile = Boolean(convoName || profileName || name); const shouldShowProfile = Boolean(convoName || profileName || name);
const styles = (boldProfileName const styles = (boldProfileName

@ -26,7 +26,7 @@ export const UserItem = () => {
const displayedPubkey = username ? shortenedPubkey : conversationId; const displayedPubkey = username ? shortenedPubkey : conversationId;
const displayName = isMe const displayName = isMe
? window.i18n('noteToSelf') ? window.i18n('noteToSelf')
: isSearchResultsMode && hasNickname : isSearchResultsMode && hasNickname && realName
? `${realName} (${username})` ? `${realName} (${username})`
: username; : username;

@ -101,7 +101,7 @@ const ConversationHeader = (props: { source: string; conversationId: string }) =
return ( return (
<StyledConversationTitleResults> <StyledConversationTitleResults>
<StyledMessageResultsHeaderName> <StyledMessageResultsHeaderName>
<ContactName pubkey={conversationId} shouldShowPubkey={false} boldProfileName={true} /> <ContactName pubkey={conversationId} shouldShowPubkey={false} boldProfileName={false} />
</StyledMessageResultsHeaderName> </StyledMessageResultsHeaderName>
</StyledConversationTitleResults> </StyledConversationTitleResults>
); );
@ -109,7 +109,7 @@ const ConversationHeader = (props: { source: string; conversationId: string }) =
return ( return (
<StyledConversationTitleResults> <StyledConversationTitleResults>
<FromName source={source} conversationId={conversationId} />; <FromName source={source} conversationId={conversationId} />
</StyledConversationTitleResults> </StyledConversationTitleResults>
); );
}; };
@ -203,6 +203,7 @@ export const MessageSearchResult = (props: MessageResultProps) => {
if (!source && !destination) { if (!source && !destination) {
return null; return null;
} }
// tslint:disable: use-simple-attributes
return ( return (
<StyledSearchResulsts <StyledSearchResulsts

@ -49,7 +49,7 @@ export const SearchResults = (props: SearchResultsProps) => {
<SearchResultsContainer> <SearchResultsContainer>
{noResults ? <NoResults>{window.i18n('noSearchResults', [searchTerm])}</NoResults> : null} {noResults ? <NoResults>{window.i18n('noSearchResults', [searchTerm])}</NoResults> : null}
{haveContactsAndGroup ? ( {haveContactsAndGroup ? (
<div> <>
<StyledSeparatorSection>{window.i18n('conversationsHeader')}</StyledSeparatorSection> <StyledSeparatorSection>{window.i18n('conversationsHeader')}</StyledSeparatorSection>
{contactsAndGroups.map(contactOrGroup => ( {contactsAndGroups.map(contactOrGroup => (
<MemoConversationListItemWithDetails <MemoConversationListItemWithDetails
@ -59,18 +59,18 @@ export const SearchResults = (props: SearchResultsProps) => {
key={`search-result-convo-${contactOrGroup.id}`} key={`search-result-convo-${contactOrGroup.id}`}
/> />
))} ))}
</div> </>
) : null} ) : null}
{haveMessages && ( {haveMessages && (
<div> <>
<StyledSeparatorSection> <StyledSeparatorSection>
{`${window.i18n('messagesHeader')}: ${messages.length}`} {`${window.i18n('messagesHeader')}: ${messages.length}`}
</StyledSeparatorSection> </StyledSeparatorSection>
{messages.map(message => ( {messages.map(message => (
<MessageSearchResult key={`search-result-message-${message.id}`} {...message} /> <MessageSearchResult key={`search-result-message-${message.id}`} {...message} />
))} ))}
</div> </>
)} )}
</SearchResultsContainer> </SearchResultsContainer>
); );

@ -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) { export function useConversationRealName(convoId?: string) {
const convoProps = useConversationPropsById(convoId); const convoProps = useConversationPropsById(convoId);
return convoProps?.isPrivate ? convoProps?.name : undefined; return convoProps?.isPrivate ? convoProps?.name : undefined;
} }

@ -1094,29 +1094,7 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
const groupAdmins = this.getGroupAdmins(); const groupAdmins = this.getGroupAdmins();
return Array.isArray(groupAdmins) && groupAdmins.includes(pubKey); 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) { public async setProfileName(name: string) {
const profileName = this.get('profileName'); const profileName = this.get('profileName');
if (profileName !== name) { if (profileName !== name) {

@ -285,7 +285,7 @@ export async function handleNewClosedGroup(
await ClosedGroup.addUpdateMessage( await ClosedGroup.addUpdateMessage(
convo, convo,
{ newName: name, joiningMembers: members }, { newName: name, joiningMembers: members },
'incoming', envelope.senderIdentity || envelope.source, // new group message are coming as session messages
envelopeTimestamp envelopeTimestamp
); );
@ -560,7 +560,7 @@ async function handleClosedGroupNameChanged(
await ClosedGroup.addUpdateMessage( await ClosedGroup.addUpdateMessage(
convo, convo,
groupDiff, groupDiff,
'incoming', envelope.senderIdentity,
_.toNumber(envelope.timestamp) _.toNumber(envelope.timestamp)
); );
convo.set({ name: newName }); convo.set({ name: newName });
@ -613,7 +613,12 @@ async function handleClosedGroupMembersAdded(
const groupDiff: ClosedGroup.GroupDiff = { const groupDiff: ClosedGroup.GroupDiff = {
joiningMembers: membersNotAlreadyPresent, joiningMembers: membersNotAlreadyPresent,
}; };
await ClosedGroup.addUpdateMessage(convo, groupDiff, 'incoming', _.toNumber(envelope.timestamp)); await ClosedGroup.addUpdateMessage(
convo,
groupDiff,
envelope.senderIdentity,
_.toNumber(envelope.timestamp)
);
convo.set({ members }); convo.set({ members });
@ -686,7 +691,7 @@ async function handleClosedGroupMembersRemoved(
await ClosedGroup.addUpdateMessage( await ClosedGroup.addUpdateMessage(
convo, convo,
groupDiff, groupDiff,
'incoming', envelope.senderIdentity,
_.toNumber(envelope.timestamp) _.toNumber(envelope.timestamp)
); );
convo.updateLastMessage(); convo.updateLastMessage();
@ -763,7 +768,12 @@ async function handleClosedGroupAdminMemberLeft(
}; };
convo.set('members', []); convo.set('members', []);
await ClosedGroup.addUpdateMessage(convo, groupDiff, 'incoming', _.toNumber(envelope.timestamp)); await ClosedGroup.addUpdateMessage(
convo,
groupDiff,
envelope.senderIdentity,
_.toNumber(envelope.timestamp)
);
convo.updateLastMessage(); convo.updateLastMessage();
await convo.commit(); await convo.commit();
@ -779,7 +789,12 @@ async function handleClosedGroupLeftOurself(
const groupDiff: ClosedGroup.GroupDiff = { const groupDiff: ClosedGroup.GroupDiff = {
leavingMembers: [envelope.senderIdentity], leavingMembers: [envelope.senderIdentity],
}; };
await ClosedGroup.addUpdateMessage(convo, groupDiff, 'incoming', _.toNumber(envelope.timestamp)); await ClosedGroup.addUpdateMessage(
convo,
groupDiff,
envelope.senderIdentity,
_.toNumber(envelope.timestamp)
);
convo.updateLastMessage(); convo.updateLastMessage();
// remove ourself from the list of members // remove ourself from the list of members
convo.set( convo.set(
@ -828,7 +843,12 @@ async function handleClosedGroupMemberLeft(envelope: EnvelopePlus, convo: Conver
leavingMembers: [sender], leavingMembers: [sender],
}; };
await ClosedGroup.addUpdateMessage(convo, groupDiff, 'incoming', _.toNumber(envelope.timestamp)); await ClosedGroup.addUpdateMessage(
convo,
groupDiff,
envelope.senderIdentity,
_.toNumber(envelope.timestamp)
);
convo.updateLastMessage(); 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 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)) { if (oldMembers.includes(sender)) {
@ -918,7 +938,12 @@ export async function createClosedGroup(groupName: string, members: Array<string
joiningMembers: listOfMembers, joiningMembers: listOfMembers,
}; };
const dbMessage = await ClosedGroup.addUpdateMessage(convo, groupDiff, 'outgoing', Date.now()); const dbMessage = await ClosedGroup.addUpdateMessage(
convo,
groupDiff,
UserUtils.getOurPubKeyStrFromCache(),
Date.now()
);
// be sure to call this before sending the message. // be sure to call this before sending the message.
// the sending pipeline needs to know from GroupUtils when a message is for a medium group // the sending pipeline needs to know from GroupUtils when a message is for a medium group

@ -15,7 +15,6 @@ import { UserUtils } from '../utils';
import { ClosedGroupMemberLeftMessage } from '../messages/outgoing/controlMessage/group/ClosedGroupMemberLeftMessage'; import { ClosedGroupMemberLeftMessage } from '../messages/outgoing/controlMessage/group/ClosedGroupMemberLeftMessage';
import { ConversationModel, ConversationTypeEnum } from '../../models/conversation'; import { ConversationModel, ConversationTypeEnum } from '../../models/conversation';
import { MessageModel } from '../../models/message'; import { MessageModel } from '../../models/message';
import { MessageModelType } from '../../models/messageType';
import { import {
addKeyPairToCacheAndDBIfNeeded, addKeyPairToCacheAndDBIfNeeded,
distributingClosedGroupEncryptionKeyPairs, distributingClosedGroupEncryptionKeyPairs,
@ -107,20 +106,35 @@ export async function initiateClosedGroupUpdate(
if (diff.newName?.length) { if (diff.newName?.length) {
const nameOnlyDiff: GroupDiff = _.pick(diff, 'newName'); const nameOnlyDiff: GroupDiff = _.pick(diff, 'newName');
const dbMessageName = await addUpdateMessage(convo, nameOnlyDiff, 'outgoing', Date.now()); const dbMessageName = await addUpdateMessage(
convo,
nameOnlyDiff,
UserUtils.getOurPubKeyStrFromCache(),
Date.now()
);
await sendNewName(convo, diff.newName, dbMessageName.id as string); await sendNewName(convo, diff.newName, dbMessageName.id as string);
} }
if (diff.joiningMembers?.length) { if (diff.joiningMembers?.length) {
const joiningOnlyDiff: GroupDiff = _.pick(diff, 'joiningMembers'); const joiningOnlyDiff: GroupDiff = _.pick(diff, 'joiningMembers');
const dbMessageAdded = await addUpdateMessage(convo, joiningOnlyDiff, 'outgoing', Date.now()); const dbMessageAdded = await addUpdateMessage(
convo,
joiningOnlyDiff,
UserUtils.getOurPubKeyStrFromCache(),
Date.now()
);
await sendAddedMembers(convo, diff.joiningMembers, dbMessageAdded.id as string, updateObj); await sendAddedMembers(convo, diff.joiningMembers, dbMessageAdded.id as string, updateObj);
} }
if (diff.leavingMembers?.length) { if (diff.leavingMembers?.length) {
const leavingOnlyDiff: GroupDiff = { kickedMembers: diff.leavingMembers }; const leavingOnlyDiff: GroupDiff = { kickedMembers: diff.leavingMembers };
const dbMessageLeaving = await addUpdateMessage(convo, leavingOnlyDiff, 'outgoing', Date.now()); const dbMessageLeaving = await addUpdateMessage(
convo,
leavingOnlyDiff,
UserUtils.getOurPubKeyStrFromCache(),
Date.now()
);
const stillMembers = members; const stillMembers = members;
await sendRemovedMembers( await sendRemovedMembers(
convo, convo,
@ -135,7 +149,7 @@ export async function initiateClosedGroupUpdate(
export async function addUpdateMessage( export async function addUpdateMessage(
convo: ConversationModel, convo: ConversationModel,
diff: GroupDiff, diff: GroupDiff,
type: MessageModelType, sender: string,
sentAt: number sentAt: number
): Promise<MessageModel> { ): Promise<MessageModel> {
const groupUpdate: any = {}; const groupUpdate: any = {};
@ -156,25 +170,28 @@ export async function addUpdateMessage(
groupUpdate.kicked = diff.kickedMembers; groupUpdate.kicked = diff.kickedMembers;
} }
const unread = type === 'incoming'; if (UserUtils.isUsFromCache(sender)) {
const outgoingMessage = await convo.addSingleOutgoingMessage({
const message = await convo.addSingleOutgoingMessage({ sent_at: sentAt,
group_update: groupUpdate,
unread: 1,
expireTimer: 0,
});
return outgoingMessage;
}
const incomingMessage = await convo.addSingleIncomingMessage({
sent_at: sentAt, sent_at: sentAt,
group_update: groupUpdate, group_update: groupUpdate,
unread: unread ? 1 : 0,
expireTimer: 0, expireTimer: 0,
source: sender,
}); });
// update the unreadCount for this convo
if (unread) { const unreadCount = await convo.getUnreadCount();
// update the unreadCount for this convo convo.set({
const unreadCount = await convo.getUnreadCount(); unreadCount,
convo.set({ });
unreadCount, await convo.commit();
}); return incomingMessage;
await convo.commit();
}
return message;
} }
function buildGroupDiff(convo: ConversationModel, update: GroupInfo): GroupDiff { 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 // Send the update to the group
const nameChangeMessage = new ClosedGroupNameChangeMessage({ const nameChangeMessage = new ClosedGroupNameChangeMessage({
timestamp: Date.now(), timestamp: Date.now(),
groupId: groupId as string, groupId,
identifier: messageId, identifier: messageId,
name, name,
}); });
@ -396,7 +413,7 @@ export async function sendRemovedMembers(
} }
const ourNumber = UserUtils.getOurPubKeyFromCache(); const ourNumber = UserUtils.getOurPubKeyFromCache();
const admins = convo.get('groupAdmins') || []; const admins = convo.get('groupAdmins') || [];
const groupId = convo.get('id') as string; const groupId = convo.get('id');
const isCurrentUserAdmin = admins.includes(ourNumber.key); const isCurrentUserAdmin = admins.includes(ourNumber.key);
const isUserLeaving = removedMembers.includes(ourNumber.key); const isUserLeaving = removedMembers.includes(ourNumber.key);

Loading…
Cancel
Save