{
if (haveOldest && row === 0) {
rowContents = (
- {renderHeroRow(id, this.resizeHeroRow)}
+ {renderHeroRow(id, this.resizeHeroRow, updateSharedGroups)}
);
} else if (!haveOldest && row === 0) {
diff --git a/ts/model-types.d.ts b/ts/model-types.d.ts
index a4127ad64bfa..47cfcbbd85f7 100644
--- a/ts/model-types.d.ts
+++ b/ts/model-types.d.ts
@@ -85,7 +85,6 @@ declare class ConversationModelType extends Backbone.Model<
cleanup(): Promise;
disableProfileSharing(): void;
dropProfileKey(): Promise;
- generateProps(): void;
getAccepted(): boolean;
getAvatarPath(): string | undefined;
getColor(): ColorType | undefined;
diff --git a/ts/sql/Client.ts b/ts/sql/Client.ts
index f9be5258a2dc..8789228f96e9 100644
--- a/ts/sql/Client.ts
+++ b/ts/sql/Client.ts
@@ -156,6 +156,8 @@ const dataInterface: ClientInterface = {
getTapToViewMessagesNeedingErase,
getOlderMessagesByConversation,
getNewerMessagesByConversation,
+ getLastConversationActivity,
+ getLastConversationPreview,
getMessageMetricsForConversation,
migrateConversationMessages,
@@ -1022,6 +1024,32 @@ async function getNewerMessagesByConversation(
return new MessageCollection(handleMessageJSON(messages));
}
+async function getLastConversationActivity(
+ conversationId: string,
+ options: {
+ Message: typeof MessageModelType;
+ }
+): Promise {
+ const { Message } = options;
+ const result = await channels.getLastConversationActivity(conversationId);
+ if (result) {
+ return new Message(result);
+ }
+ return;
+}
+async function getLastConversationPreview(
+ conversationId: string,
+ options: {
+ Message: typeof MessageModelType;
+ }
+): Promise {
+ const { Message } = options;
+ const result = await channels.getLastConversationPreview(conversationId);
+ if (result) {
+ return new Message(result);
+ }
+ return;
+}
async function getMessageMetricsForConversation(conversationId: string) {
const result = await channels.getMessageMetricsForConversation(
conversationId
diff --git a/ts/sql/Interface.ts b/ts/sql/Interface.ts
index e028e67324a2..4635bdc4a7b5 100644
--- a/ts/sql/Interface.ts
+++ b/ts/sql/Interface.ts
@@ -210,6 +210,12 @@ export type ServerInterface = DataInterface & {
conversationId: string,
options?: { limit?: number; receivedAt?: number }
) => Promise>;
+ getLastConversationActivity: (
+ conversationId: string
+ ) => Promise;
+ getLastConversationPreview: (
+ conversationId: string
+ ) => Promise;
getNextExpiringMessage: () => Promise;
getNextTapToViewMessageToAgeOut: () => Promise;
getOutgoingWithoutExpiresAt: () => Promise>;
@@ -308,6 +314,18 @@ export type ClientInterface = DataInterface & {
MessageCollection: typeof MessageModelCollectionType;
}
) => Promise;
+ getLastConversationActivity: (
+ conversationId: string,
+ options: {
+ Message: typeof MessageModelType;
+ }
+ ) => Promise;
+ getLastConversationPreview: (
+ conversationId: string,
+ options: {
+ Message: typeof MessageModelType;
+ }
+ ) => Promise;
getNextExpiringMessage: ({
Message,
}: {
diff --git a/ts/sql/Server.ts b/ts/sql/Server.ts
index 3e4610911f9b..00fce6399d7c 100644
--- a/ts/sql/Server.ts
+++ b/ts/sql/Server.ts
@@ -132,6 +132,8 @@ const dataInterface: ServerInterface = {
getOlderMessagesByConversation,
getNewerMessagesByConversation,
getMessageMetricsForConversation,
+ getLastConversationActivity,
+ getLastConversationPreview,
migrateConversationMessages,
getUnprocessedCount,
@@ -2749,6 +2751,50 @@ async function getNewestMessageForConversation(conversationId: string) {
return row;
}
+
+async function getLastConversationActivity(
+ conversationId: string
+): Promise {
+ const db = getInstance();
+ const row = await db.get(
+ `SELECT * FROM messages WHERE
+ conversationId = $conversationId AND
+ type NOT IN ('profile-change', 'verified-change', 'message-history-unsynced') AND
+ json_extract(json, '$.expirationTimerUpdate.fromSync') != true
+ ORDER BY received_at DESC
+ LIMIT 1;`,
+ {
+ $conversationId: conversationId,
+ }
+ );
+
+ if (!row) {
+ return null;
+ }
+
+ return jsonToObject(row.json);
+}
+async function getLastConversationPreview(
+ conversationId: string
+): Promise {
+ const db = getInstance();
+ const row = await db.get(
+ `SELECT * FROM messages WHERE
+ conversationId = $conversationId AND
+ type NOT IN ('profile-change', 'verified-change', 'message-history-unsynced')
+ ORDER BY received_at DESC
+ LIMIT 1;`,
+ {
+ $conversationId: conversationId,
+ }
+ );
+
+ if (!row) {
+ return null;
+ }
+
+ return jsonToObject(row.json);
+}
async function getOldestUnreadMessageForConversation(conversationId: string) {
const db = getInstance();
const row = await db.get(
diff --git a/ts/state/smart/Timeline.tsx b/ts/state/smart/Timeline.tsx
index f82de38fdb33..5286cab0f61e 100644
--- a/ts/state/smart/Timeline.tsx
+++ b/ts/state/smart/Timeline.tsx
@@ -68,8 +68,18 @@ function renderEmojiPicker({
function renderLastSeenIndicator(id: string): JSX.Element {
return ;
}
-function renderHeroRow(id: string, onHeightChange: () => unknown): JSX.Element {
- return ;
+function renderHeroRow(
+ id: string,
+ onHeightChange: () => unknown,
+ updateSharedGroups: () => unknown
+): JSX.Element {
+ return (
+
+ );
}
function renderLoadingRow(id: string): JSX.Element {
return ;
diff --git a/ts/test/types/Conversation_test.ts b/ts/test/types/Conversation_test.ts
deleted file mode 100644
index 5a186ac3c0d5..000000000000
--- a/ts/test/types/Conversation_test.ts
+++ /dev/null
@@ -1,152 +0,0 @@
-import { assert } from 'chai';
-
-import * as Conversation from '../../types/Conversation';
-import {
- IncomingMessage,
- MessageHistoryUnsyncedMessage,
- OutgoingMessage,
- ProfileChangeNotificationMessage,
- VerifiedChangeMessage,
-} from '../../types/Message';
-
-describe('Conversation', () => {
- describe('createLastMessageUpdate', () => {
- it('should reset last message if conversation has no messages', () => {
- const input = {};
- const expected = {
- lastMessage: '',
- lastMessageStatus: null,
- timestamp: null,
- };
-
- const actual = Conversation.createLastMessageUpdate(input);
- assert.deepEqual(actual, expected);
- });
-
- context('for regular message', () => {
- it('should update last message text and timestamp', () => {
- const input = {
- currentTimestamp: 555,
- lastMessageStatus: 'read',
- lastMessage: {
- type: 'outgoing',
- conversationId: 'foo',
- sent_at: 666,
- timestamp: 666,
- } as OutgoingMessage,
- lastMessageNotificationText: 'New outgoing message',
- };
- const expected = {
- lastMessage: 'New outgoing message',
- lastMessageStatus: 'read',
- lastMessageDeletedForEveryone: undefined,
- timestamp: 666,
- };
-
- const actual = Conversation.createLastMessageUpdate(input);
- assert.deepEqual(actual, expected);
- });
- });
-
- context('for message history unsynced message', () => {
- it('should skip update', () => {
- const input = {
- currentTimestamp: 555,
- lastMessage: {
- type: 'message-history-unsynced',
- conversationId: 'foo',
- sent_at: 666,
- timestamp: 666,
- } as MessageHistoryUnsyncedMessage,
- lastMessageNotificationText: 'xoxoxoxo',
- };
- const expected = {
- lastMessage: 'xoxoxoxo',
- lastMessageStatus: null,
- lastMessageDeletedForEveryone: undefined,
- timestamp: 555,
- };
-
- const actual = Conversation.createLastMessageUpdate(input);
- assert.deepEqual(actual, expected);
- });
- });
-
- context('for verified change message', () => {
- it('should skip update', () => {
- const input = {
- currentTimestamp: 555,
- lastMessage: {
- type: 'verified-change',
- conversationId: 'foo',
- sent_at: 666,
- timestamp: 666,
- } as VerifiedChangeMessage,
- lastMessageNotificationText: 'Verified Changed',
- };
- const expected = {
- lastMessage: '',
- lastMessageStatus: null,
- lastMessageDeletedForEveryone: undefined,
- timestamp: 555,
- };
-
- const actual = Conversation.createLastMessageUpdate(input);
- assert.deepEqual(actual, expected);
- });
- });
-
- context('for expire timer update from sync', () => {
- it('should update message but not timestamp (to prevent bump to top)', () => {
- const input = {
- currentTimestamp: 555,
- lastMessage: {
- type: 'incoming',
- conversationId: 'foo',
- sent_at: 666,
- timestamp: 666,
- expirationTimerUpdate: {
- expireTimer: 111,
- fromSync: true,
- source: '+12223334455',
- },
- } as IncomingMessage,
- lastMessageNotificationText: 'Last message before expired',
- };
- const expected = {
- lastMessage: 'Last message before expired',
- lastMessageStatus: null,
- lastMessageDeletedForEveryone: undefined,
- timestamp: 555,
- };
-
- const actual = Conversation.createLastMessageUpdate(input);
- assert.deepEqual(actual, expected);
- });
- });
-
- context('for profile change message', () => {
- it('should update message but not timestamp (to prevent bump to top)', () => {
- const input = {
- currentTimestamp: 555,
- lastMessage: {
- type: 'profile-change',
- conversationId: 'foo',
- sent_at: 666,
- timestamp: 666,
- } as ProfileChangeNotificationMessage,
- lastMessageNotificationText: 'John changed their profile name',
- };
- const expected = {
- lastMessage: 'John changed their profile name',
- lastMessageStatus: null,
- lastMessageDeletedForEveryone: undefined,
- timestamp: 555,
- };
-
- const actual = Conversation.createLastMessageUpdate(input);
- assert.deepEqual(actual, expected);
- });
- });
- });
-});
diff --git a/ts/textsecure/MessageReceiver.ts b/ts/textsecure/MessageReceiver.ts
index e8a692c1f539..2f12be4d6d73 100644
--- a/ts/textsecure/MessageReceiver.ts
+++ b/ts/textsecure/MessageReceiver.ts
@@ -1401,7 +1401,7 @@ class MessageReceiverInner extends EventTarget {
}
const to = sentMessage.message.group
? `group(${sentMessage.message.group.id.toBinary()})`
- : sentMessage.destination;
+ : sentMessage.destination || sentMessage.destinationUuid;
window.log.info(
'sent message to',
diff --git a/ts/types/Conversation.ts b/ts/types/Conversation.ts
deleted file mode 100644
index 6f3e8079b01f..000000000000
--- a/ts/types/Conversation.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-import { Message } from './Message';
-
-interface ConversationLastMessageUpdate {
- lastMessage: string;
- lastMessageStatus: string | null;
- timestamp: number | null;
- lastMessageDeletedForEveryone?: boolean;
-}
-
-export const createLastMessageUpdate = ({
- currentTimestamp,
- lastMessage,
- lastMessageStatus,
- lastMessageNotificationText,
-}: {
- currentTimestamp?: number;
- lastMessage?: Message;
- lastMessageStatus?: string;
- lastMessageNotificationText?: string;
-}): ConversationLastMessageUpdate => {
- if (!lastMessage) {
- return {
- lastMessage: '',
- lastMessageStatus: null,
- timestamp: null,
- };
- }
-
- const { type, expirationTimerUpdate, deletedForEveryone } = lastMessage;
- const isMessageHistoryUnsynced = type === 'message-history-unsynced';
- const isProfileChangedMessage = type === 'profile-change';
- const isVerifiedChangeMessage = type === 'verified-change';
- const isExpireTimerUpdateFromSync = Boolean(
- expirationTimerUpdate && expirationTimerUpdate.fromSync
- );
-
- const shouldUpdateTimestamp = Boolean(
- !isMessageHistoryUnsynced &&
- !isProfileChangedMessage &&
- !isVerifiedChangeMessage &&
- !isExpireTimerUpdateFromSync
- );
- const newTimestamp = shouldUpdateTimestamp
- ? lastMessage.sent_at
- : currentTimestamp;
-
- const shouldUpdateLastMessageText = !isVerifiedChangeMessage;
- const newLastMessageText = shouldUpdateLastMessageText
- ? lastMessageNotificationText
- : '';
-
- return {
- lastMessage: deletedForEveryone ? '' : newLastMessageText || '',
- lastMessageStatus: lastMessageStatus || null,
- timestamp: newTimestamp || null,
- lastMessageDeletedForEveryone: deletedForEveryone,
- };
-};
diff --git a/ts/util/lint/exceptions.json b/ts/util/lint/exceptions.json
index 1083632d26ca..88fb195f9b90 100644
--- a/ts/util/lint/exceptions.json
+++ b/ts/util/lint/exceptions.json
@@ -207,7 +207,7 @@
"rule": "jQuery-wrap(",
"path": "js/models/conversations.js",
"line": " await wrap(",
- "lineNumber": 671,
+ "lineNumber": 665,
"reasonCategory": "falseMatch",
"updated": "2020-06-09T20:26:46.515Z"
},