Honor preferContactAvatars field on AccountRecord

This commit is contained in:
Scott Nonnenberg 2022-01-25 09:44:45 -08:00 committed by GitHub
parent f5eb17e0d1
commit 68a458ec4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 163 additions and 4 deletions

View File

@ -133,6 +133,7 @@ message AccountRecord {
optional PhoneNumberSharingMode phoneNumberSharingMode = 12;
optional bool notDiscoverableByPhoneNumber = 13;
repeated PinnedConversation pinnedConversations = 14;
optional bool preferContactAvatars = 15;
optional uint32 universalExpireTimer = 17;
optional bool primarySendsSms = 18;
optional string e164 = 19;

View File

@ -20,6 +20,7 @@ import { UUID, isValidUuid } from './types/UUID';
import { Address } from './types/Address';
import { QualifiedAddress } from './types/QualifiedAddress';
import * as log from './logging/log';
import { sleep } from './util/sleep';
const MAX_MESSAGE_BODY_LENGTH = 64 * 1024;
@ -784,6 +785,36 @@ export class ConversationController {
return this._initialPromise;
}
// A number of things outside conversation.attributes affect conversation re-rendering.
// If it's scoped to a given conversation, it's easy to trigger('change'). There are
// important values in storage and the storage service which change rendering pretty
// radically, so this function is necessary to force regeneration of props.
async forceRerender(): Promise<void> {
let count = 0;
const conversations = this._conversations.models.slice();
log.info(
`forceRerender: Starting to loop through ${conversations.length} conversations`
);
for (let i = 0, max = conversations.length; i < max; i += 1) {
const conversation = conversations[i];
if (conversation.cachedProps) {
conversation.oldCachedProps = conversation.cachedProps;
conversation.cachedProps = null;
conversation.trigger('props-change', conversation, false);
count += 1;
}
if (count % 10 === 0) {
// eslint-disable-next-line no-await-in-loop
await sleep(300);
}
}
log.info(`forceRerender: Updated ${count} conversations`);
}
onConvoOpenStart(conversationId: string): void {
this._conversationOpenStart.set(conversationId, Date.now());
}

View File

@ -684,8 +684,10 @@ export async function startApp(): Promise<void> {
}
if (
window.isBeforeVersion(lastVersion, 'v1.36.0-beta.1') &&
window.isAfterVersion(lastVersion, 'v1.35.0-beta.1')
(window.isBeforeVersion(lastVersion, 'v1.36.0-beta.1') &&
window.isAfterVersion(lastVersion, 'v1.35.0-beta.1')) ||
// 5.30 introduced understanding of new storage service AccountRecord fields
window.isBeforeVersion(lastVersion, 'v5.30.0-alpha')
) {
await window.Signal.Services.eraseAllStorageServiceState();
}

View File

@ -4896,7 +4896,10 @@ export class ConversationModel extends window.Backbone
}
private getAvatarPath(): undefined | string {
const avatar = isMe(this.attributes)
const shouldShowProfileAvatar =
isMe(this.attributes) ||
window.storage.get('preferContactAvatars') === false;
const avatar = shouldShowProfileAvatar
? this.get('profileAvatar') || this.get('avatar')
: this.get('avatar') || this.get('profileAvatar');
return avatar?.path || undefined;

View File

@ -182,6 +182,11 @@ export async function toAccountRecord(
);
accountRecord.linkPreviews = Boolean(window.Events.getLinkPreviewSetting());
const preferContactAvatars = window.storage.get('preferContactAvatars');
if (preferContactAvatars !== undefined) {
accountRecord.preferContactAvatars = Boolean(preferContactAvatars);
}
const primarySendsSms = window.storage.get('primarySendsSms');
if (primarySendsSms !== undefined) {
accountRecord.primarySendsSms = Boolean(primarySendsSms);
@ -855,6 +860,7 @@ export async function mergeAccountRecord(
readReceipts,
sealedSenderIndicators,
typingIndicators,
preferContactAvatars,
primarySendsSms,
universalExpireTimer,
e164: accountE164,
@ -878,6 +884,15 @@ export async function mergeAccountRecord(
window.storage.put('linkPreviews', linkPreviews);
}
if (typeof preferContactAvatars === 'boolean') {
const previous = window.storage.get('preferContactAvatars');
window.storage.put('preferContactAvatars', preferContactAvatars);
if (Boolean(previous) !== Boolean(preferContactAvatars)) {
window.ConversationController.forceRerender();
}
}
if (typeof primarySendsSms === 'boolean') {
window.storage.put('primarySendsSms', primarySendsSms);
}

View File

@ -0,0 +1,57 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import { areArraysMatchingSets } from '../../util/areArraysMatchingSets';
describe('areArraysMatchingSets', () => {
it('returns true if arrays are both empty', () => {
const left: Array<string> = [];
const right: Array<string> = [];
assert.isTrue(areArraysMatchingSets(left, right));
});
it('returns true if arrays are equal', () => {
const left = [1, 2, 3];
const right = [1, 2, 3];
assert.isTrue(areArraysMatchingSets(left, right));
});
it('returns true if arrays are equal but out of order', () => {
const left = [1, 2, 3];
const right = [3, 1, 2];
assert.isTrue(areArraysMatchingSets(left, right));
});
it('returns true if arrays are equal but one has duplicates', () => {
const left = [1, 2, 3, 1];
const right = [1, 2, 3];
assert.isTrue(areArraysMatchingSets(left, right));
});
it('returns false if first array has missing elements', () => {
const left = [1, 2];
const right = [1, 2, 3];
assert.isFalse(areArraysMatchingSets(left, right));
});
it('returns false if second array has missing elements', () => {
const left = [1, 2, 3];
const right = [1, 2];
assert.isFalse(areArraysMatchingSets(left, right));
});
it('returns false if second array is empty', () => {
const left = [1, 2, 3];
const right: Array<number> = [];
assert.isFalse(areArraysMatchingSets(left, right));
});
});

View File

@ -105,6 +105,7 @@ import {
GroupSyncEvent,
} from './messageReceiverEvents';
import * as log from '../logging/log';
import { areArraysMatchingSets } from '../util/areArraysMatchingSets';
const GROUPV1_ID_LENGTH = 16;
const GROUPV2_ID_LENGTH = 32;
@ -2629,19 +2630,32 @@ export default class MessageReceiver
envelope: ProcessedEnvelope,
blocked: Proto.SyncMessage.IBlocked
): Promise<void> {
let changed = false;
if (blocked.numbers) {
const previous = this.storage.get('blocked', []);
log.info('handleBlocked: Blocking these numbers:', blocked.numbers);
await this.storage.put('blocked', blocked.numbers);
if (!areArraysMatchingSets(previous, blocked.numbers)) {
changed = true;
}
}
if (blocked.uuids) {
const previous = this.storage.get('blocked-uuids', []);
const uuids = blocked.uuids.map((uuid, index) => {
return normalizeUuid(uuid, `handleBlocked.uuids.${index}`);
});
log.info('handleBlocked: Blocking these uuids:', uuids);
await this.storage.put('blocked-uuids', uuids);
if (!areArraysMatchingSets(previous, uuids)) {
changed = true;
}
}
if (blocked.groupIds) {
const previous = this.storage.get('blocked-groups', []);
const groupV1Ids: Array<string> = [];
const groupIds: Array<string> = [];
@ -2661,10 +2675,21 @@ export default class MessageReceiver
'v1:',
groupV1Ids.map(groupId => `group(${groupId})`)
);
await this.storage.put('blocked-groups', [...groupIds, ...groupV1Ids]);
const ids = [...groupIds, ...groupV1Ids];
await this.storage.put('blocked-groups', ids);
if (!areArraysMatchingSets(previous, ids)) {
changed = true;
}
}
this.removeFromCache(envelope);
if (changed) {
log.info('handleBlocked: Block list changed, forcing re-render.');
window.ConversationController.forceRerender();
}
}
private isBlocked(number: string): boolean {

View File

@ -94,6 +94,7 @@ export type StorageAccessType = {
phoneNumberSharingMode: PhoneNumberSharingMode;
phoneNumberDiscoverability: PhoneNumberDiscoverability;
pinnedConversationIds: Array<string>;
preferContactAvatars: boolean;
primarySendsSms: boolean;
// Unlike `number_id` (which also includes device id) this field is only
// updated whenever we receive a new storage manifest

View File

@ -0,0 +1,24 @@
// Copyright 2020-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
export function areArraysMatchingSets<T>(
left: Array<T>,
right: Array<T>
): boolean {
const leftSet = new Set(left);
const rightSet = new Set(right);
for (const item of leftSet) {
if (!rightSet.has(item)) {
return false;
}
}
for (const item of rightSet) {
if (!leftSet.has(item)) {
return false;
}
}
return true;
}