From dbf6a0183f2c63e9b5bb776ce4d4d68e697fa355 Mon Sep 17 00:00:00 2001 From: audric Date: Mon, 26 Jul 2021 11:30:53 +1000 Subject: [PATCH 1/3] remove unread top banner on scroll to bottom --- .../conversation/SessionMessagesListContainer.tsx | 9 +++++++-- ts/state/ducks/conversations.ts | 12 ++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/ts/components/session/conversation/SessionMessagesListContainer.tsx b/ts/components/session/conversation/SessionMessagesListContainer.tsx index c7514d497..81adf29d3 100644 --- a/ts/components/session/conversation/SessionMessagesListContainer.tsx +++ b/ts/components/session/conversation/SessionMessagesListContainer.tsx @@ -6,6 +6,7 @@ import _ from 'lodash'; import { contextMenu } from 'react-contexify'; import { fetchMessagesForConversation, + markConversationFullyRead, quotedMessageToAnimate, ReduxConversationType, setNextMessageToPlay, @@ -173,7 +174,9 @@ class SessionMessagesListContainerInner extends React.Component { } if ((forceIsOnBottom || this.getScrollOffsetBottomPx() === 0) && isElectronWindowFocused()) { - void conversation.markRead(messagesProps[0].propsForMessage.receivedAt || 0); + void conversation.markRead(messagesProps[0].propsForMessage.receivedAt || 0).then(() => { + window.inboxStore?.dispatch(markConversationFullyRead(conversationKey)); + }); } } @@ -369,7 +372,9 @@ class SessionMessagesListContainerInner extends React.Component { const conversation = getConversationController().get(conversationKey); if (isElectronWindowFocused()) { - void conversation.markRead(messagesProps[0].propsForMessage.receivedAt || 0); + void conversation.markRead(messagesProps[0].propsForMessage.receivedAt || 0).then(() => { + window.inboxStore?.dispatch(markConversationFullyRead(conversationKey)); + }); } } diff --git a/ts/state/ducks/conversations.ts b/ts/state/ducks/conversations.ts index af5c3d219..0940c65b2 100644 --- a/ts/state/ducks/conversations.ts +++ b/ts/state/ducks/conversations.ts @@ -601,6 +601,17 @@ const conversationsSlice = createSlice({ return handleConversationReset(state, action); }, + markConversationFullyRead(state: ConversationsStateType, action: PayloadAction) { + if (state.selectedConversation !== action.payload) { + return state; + } + + return { + ...state, + firstUnreadMessageId: undefined, + }; + }, + openConversationExternal( state: ConversationsStateType, action: PayloadAction<{ @@ -711,6 +722,7 @@ export const { messageChanged, messagesChanged, openConversationExternal, + markConversationFullyRead, // layout stuff showMessageDetailsView, closeMessageDetailsView, From 1054278a540b75700ec00fef65f2de060f3a3e9e Mon Sep 17 00:00:00 2001 From: audric Date: Tue, 27 Jul 2021 10:29:18 +1000 Subject: [PATCH 2/3] disable search in messages for now --- _locales/en/messages.json | 2 +- app/sql.js | 46 ++++++++++---------- ts/components/SearchResults.tsx | 4 +- ts/components/session/UserSearchDropdown.tsx | 9 ++-- ts/data/data.ts | 23 +--------- 5 files changed, 32 insertions(+), 52 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index d3084030f..15d48eebe 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -354,7 +354,7 @@ "beginYourSession": "Begin
your
Session.", "welcomeToYourSession": "Welcome to your Session", "newSession": "New Session", - "searchFor...": "Search for conversations, contacts, and messages", + "searchFor...": "Search for conversations or contacts", "enterSessionID": "Enter Session ID", "enterSessionIDOfRecipient": "Enter Session ID or ONS name of recipient", "usersCanShareTheir...": "Users can share their Session ID by going into their account settings and tapping \"Share Session ID\", or by sharing their QR code.", diff --git a/app/sql.js b/app/sql.js index d2b7a00b9..7ddb8a210 100644 --- a/app/sql.js +++ b/app/sql.js @@ -41,7 +41,6 @@ module.exports = { getAllOpenGroupV1Conversations, getAllOpenGroupV2Conversations, getPubkeysInPublicConversation, - getAllConversationIds, getAllGroupsInvolvingId, removeAllConversations, @@ -65,8 +64,6 @@ module.exports = { getMessageBySenderAndServerTimestamp, getMessageIdsFromServerIds, getMessageById, - getAllMessages, - getAllMessageIds, getMessagesBySentAt, getSeenMessagesByHashList, getLastHashBySnode, @@ -260,7 +257,7 @@ function openAndMigrateDatabase(filePath, key) { switchToWAL(db2); // Because foreign key support is not enabled by default! - db2.pragma('foreign_keys = ON'); + db2.pragma('foreign_keys = OFF'); return db2; } catch (error) { @@ -834,6 +831,7 @@ const LOKI_SCHEMA_VERSIONS = [ updateToLokiSchemaVersion12, updateToLokiSchemaVersion13, updateToLokiSchemaVersion14, + updateToLokiSchemaVersion15, ]; function updateToLokiSchemaVersion1(currentVersion, db) { @@ -1177,6 +1175,26 @@ function updateToLokiSchemaVersion14(currentVersion, db) { console.log(`updateToLokiSchemaVersion${targetVersion}: success!`); } +function updateToLokiSchemaVersion15(currentVersion, db) { + const targetVersion = 15; + if (currentVersion >= targetVersion) { + return; + } + console.log(`updateToLokiSchemaVersion${targetVersion}: starting...`); + + db.transaction(() => { + db.exec(` + DROP TABLE pairingAuthorisations; + DROP TABLE ${MESSAGES_FTS_TABLE}; + DROP TRIGGER messages_on_delete; + DROP TRIGGER messages_on_update; + `); + + writeLokiSchemaVersion(targetVersion, db); + })(); + console.log(`updateToLokiSchemaVersion${targetVersion}: success!`); +} + function writeLokiSchemaVersion(newVersion, db) { db.prepare( `INSERT INTO loki_schema( @@ -1287,7 +1305,8 @@ function initialize({ configDir, key, messages, passwordAttempt }) { // Clear any already deleted db entries on each app start. vacuumDatabase(db); - getMessageCount(); + const msgCount = getMessageCount(); + console.warn('total message count: ', msgCount); } catch (error) { if (passwordAttempt) { throw error; @@ -1612,13 +1631,6 @@ function getAllConversations() { return map(rows, row => jsonToObject(row.json)); } -function getAllConversationIds() { - const rows = globalInstance - .prepare(`SELECT id FROM ${CONVERSATIONS_TABLE} ORDER BY id ASC;`) - .all(); - return map(rows, row => row.id); -} - function getAllOpenGroupV1Conversations() { const rows = globalInstance .prepare( @@ -1992,16 +2004,6 @@ function getMessageById(id) { return jsonToObject(row.json); } -function getAllMessages() { - const rows = globalInstance.prepare(`SELECT json FROM ${MESSAGES_TABLE} ORDER BY id ASC;`).all(); - return map(rows, row => jsonToObject(row.json)); -} - -function getAllMessageIds() { - const rows = globalInstance.prepare(`SELECT id FROM ${MESSAGES_TABLE} ORDER BY id ASC;`).all(); - return map(rows, row => row.id); -} - function getMessageBySender({ source, sourceDevice, sentAt }) { const rows = globalInstance .prepare( diff --git a/ts/components/SearchResults.tsx b/ts/components/SearchResults.tsx index d0f2e8e9f..e00531b11 100644 --- a/ts/components/SearchResults.tsx +++ b/ts/components/SearchResults.tsx @@ -54,7 +54,7 @@ export const SearchResults = (props: SearchResultsProps) => { ) : null} - {haveMessages ? ( + {/* {haveMessages ? (
{hideMessagesHeader ? null : (
@@ -65,7 +65,7 @@ export const SearchResults = (props: SearchResultsProps) => { ))}
- ) : null} + ) : null} */}
); }; diff --git a/ts/components/session/UserSearchDropdown.tsx b/ts/components/session/UserSearchDropdown.tsx index 695307bec..30293e08a 100644 --- a/ts/components/session/UserSearchDropdown.tsx +++ b/ts/components/session/UserSearchDropdown.tsx @@ -5,6 +5,7 @@ import { SessionSearchInput } from './SessionSearchInput'; import { SearchResultsProps } from '../SearchResults'; import { DefaultTheme } from 'styled-components'; +import autoBind from 'auto-bind'; export interface Props { searchTerm: string; @@ -18,13 +19,9 @@ interface State { } export class UserSearchDropdown extends React.Component { - private readonly updateSearchBound: (searchedString: string) => void; - public constructor(props: Props) { super(props); - this.updateSearchBound = this.updateSearch.bind(this); - this.handleNavigation = this.handleNavigation.bind(this); - this.handleContactSelected = this.handleContactSelected.bind(this); + autoBind(this); this.state = { selectedContact: -1, }; @@ -64,7 +61,7 @@ export class UserSearchDropdown extends React.Component {
diff --git a/ts/data/data.ts b/ts/data/data.ts index 5d9c357f1..a6882607d 100644 --- a/ts/data/data.ts +++ b/ts/data/data.ts @@ -89,7 +89,6 @@ const channelsToMake = { removeConversation, getAllConversations, - getAllConversationIds, getAllOpenGroupV1Conversations, getPubkeysInPublicConversation, getAllGroupsInvolvingId, @@ -116,8 +115,6 @@ const channelsToMake = { getMessageBySenderAndServerTimestamp, getMessageIdsFromServerIds, getMessageById, - getAllMessages, - getAllMessageIds, getMessagesBySentAt, getExpiredMessages, getOutgoingWithoutExpiresAt, @@ -541,11 +538,6 @@ export async function getAllConversations(): Promise { return collection; } -export async function getAllConversationIds(): Promise> { - const ids = await channels.getAllConversationIds(); - return ids; -} - export async function getAllOpenGroupV1Conversations(): Promise { const conversations = await channels.getAllOpenGroupV1Conversations(); @@ -664,17 +656,6 @@ export async function getMessageById(id: string): Promise { return new MessageModel(message); } -// For testing only -export async function getAllMessages(): Promise { - const messages = await channels.getAllMessages(); - return new MessageCollection(messages); -} - -export async function getAllMessageIds(): Promise> { - const ids = await channels.getAllMessageIds(); - return ids; -} - export async function getMessageBySender({ source, sourceDevice, @@ -775,9 +756,8 @@ export async function removeAllMessagesInConversation(conversationId: string): P // time so we don't use too much memory. // eslint-disable-next-line no-await-in-loop messages = await getMessagesByConversation(conversationId, { - limit: 100, + limit: 500, }); - if (!messages.length) { return; } @@ -787,6 +767,7 @@ export async function removeAllMessagesInConversation(conversationId: string): P // Note: It's very important that these models are fully hydrated because // we need to delete all associated on-disk files along with the database delete. // eslint-disable-next-line no-await-in-loop + await Promise.all(messages.map(message => message.cleanup())); // eslint-disable-next-line no-await-in-loop From 4b8778d071806f6acdea08c38ce624f976f643b0 Mon Sep 17 00:00:00 2001 From: audric Date: Tue, 27 Jul 2021 11:16:23 +1000 Subject: [PATCH 3/3] fix markRead using timestamp of now when scroll to bottom --- app/sql.js | 1 - .../session/conversation/SessionMessagesListContainer.tsx | 4 ++-- ts/models/conversation.ts | 7 +++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/sql.js b/app/sql.js index 7ddb8a210..24d3a5fd7 100644 --- a/app/sql.js +++ b/app/sql.js @@ -1185,7 +1185,6 @@ function updateToLokiSchemaVersion15(currentVersion, db) { db.transaction(() => { db.exec(` DROP TABLE pairingAuthorisations; - DROP TABLE ${MESSAGES_FTS_TABLE}; DROP TRIGGER messages_on_delete; DROP TRIGGER messages_on_update; `); diff --git a/ts/components/session/conversation/SessionMessagesListContainer.tsx b/ts/components/session/conversation/SessionMessagesListContainer.tsx index 81adf29d3..f4c72bde0 100644 --- a/ts/components/session/conversation/SessionMessagesListContainer.tsx +++ b/ts/components/session/conversation/SessionMessagesListContainer.tsx @@ -174,7 +174,7 @@ class SessionMessagesListContainerInner extends React.Component { } if ((forceIsOnBottom || this.getScrollOffsetBottomPx() === 0) && isElectronWindowFocused()) { - void conversation.markRead(messagesProps[0].propsForMessage.receivedAt || 0).then(() => { + void conversation.markRead(Date.now()).then(() => { window.inboxStore?.dispatch(markConversationFullyRead(conversationKey)); }); } @@ -372,7 +372,7 @@ class SessionMessagesListContainerInner extends React.Component { const conversation = getConversationController().get(conversationKey); if (isElectronWindowFocused()) { - void conversation.markRead(messagesProps[0].propsForMessage.receivedAt || 0).then(() => { + void conversation.markRead(Date.now()).then(() => { window.inboxStore?.dispatch(markConversationFullyRead(conversationKey)); }); } diff --git a/ts/models/conversation.ts b/ts/models/conversation.ts index 2bfb47f22..8d3edfab1 100644 --- a/ts/models/conversation.ts +++ b/ts/models/conversation.ts @@ -198,7 +198,10 @@ export class ConversationModel extends Backbone.Model { }); this.throttledNotify = _.debounce(this.notify, 500, { maxWait: 1000, trailing: true }); //start right away the function is called, and wait 1sec before calling it again - const markReadDebounced = _.debounce(this.markReadBouncy, 1000, { leading: true }); + const markReadDebounced = _.debounce(this.markReadBouncy, 1000, { + leading: true, + trailing: true, + }); // tslint:disable-next-line: no-async-without-await this.markRead = async (newestUnreadDate: number) => { const lastReadTimestamp = this.lastReadTimestamp; @@ -972,7 +975,7 @@ export class ConversationModel extends Backbone.Model { let allUnreadMessagesInConvo = (await this.getUnread()).models; const oldUnreadNowRead = allUnreadMessagesInConvo.filter( - (message: any) => message.get('received_at') <= newestUnreadDate + message => (message.get('received_at') as number) <= newestUnreadDate ); let read = [];