mirror of
https://github.com/lux-tel/session-desktop.git
synced 2026-10-30 20:33:24 +00:00
276 lines
11 KiB
TypeScript
276 lines
11 KiB
TypeScript
import { defaults } from 'lodash';
|
|
import { DisappearingMessageConversationModeType } from '../session/disappearing_messages/types';
|
|
|
|
import { ConversationTypeEnum, CONVERSATION_PRIORITIES } from './types';
|
|
import { ConversationInteractionType, ConversationInteractionStatus } from '../interactions/types';
|
|
import { LastMessageStatusType } from '../state/ducks/types';
|
|
|
|
export function isOpenOrClosedGroup(conversationType: ConversationTypeEnum) {
|
|
return (
|
|
conversationType === ConversationTypeEnum.GROUP ||
|
|
conversationType === ConversationTypeEnum.GROUPV2
|
|
);
|
|
}
|
|
|
|
export function isDirectConversation(conversationType: ConversationTypeEnum) {
|
|
return conversationType === ConversationTypeEnum.PRIVATE;
|
|
}
|
|
|
|
/**
|
|
* all: all notifications enabled, the default
|
|
* disabled: no notifications at all
|
|
* mentions_only: trigger a notification only on mentions of ourself
|
|
*/
|
|
export const ConversationNotificationSetting = ['all', 'disabled', 'mentions_only'] as const;
|
|
export type ConversationNotificationSettingType = (typeof ConversationNotificationSetting)[number];
|
|
|
|
/**
|
|
* Some fields are retrieved from the database as a select, but should not be saved in a commit()
|
|
* TODO (do we, and can we use this)
|
|
*/
|
|
export type ConversationAttributesNotSaved = {
|
|
mentionedUs: boolean;
|
|
unreadCount: number;
|
|
};
|
|
|
|
export type ConversationAttributesWithNotSavedOnes = ConversationAttributes &
|
|
ConversationAttributesNotSaved;
|
|
|
|
export interface ConversationAttributes {
|
|
id: string;
|
|
type: ConversationTypeEnum.PRIVATE | ConversationTypeEnum.GROUPV2 | ConversationTypeEnum.GROUP;
|
|
|
|
// 0 means inactive (undefined and null too but we try to get rid of them and only have 0 = inactive)
|
|
active_at: number; // this field is the one used to sort conversations in the left pane from most recent
|
|
|
|
/**
|
|
* lastMessage is actually just a preview of the last message text, shortened to 60 chars.
|
|
* This is to avoid filling the redux store with a huge last message when it's only used in the
|
|
* preview of a conversation (left pane).
|
|
* The shortening is made in sql.ts directly.
|
|
*/
|
|
lastMessage: string | null;
|
|
lastMessageStatus: LastMessageStatusType;
|
|
lastMessageInteractionType: ConversationInteractionType | null;
|
|
lastMessageInteractionStatus: ConversationInteractionStatus | null;
|
|
|
|
left: boolean; // legacy & groupv2, should eventually be removed to rely on libsession value directly
|
|
|
|
/**
|
|
* We now require all avatars stored on desktop to have in additions of their normal avatars
|
|
* a static version of it. Static as in not-animated.
|
|
* So:
|
|
* - if the avatarPath points to a file that is animated, staticAvatarPath must point to file containing its first frame,
|
|
* - if the avatarPath points to a file that is not animated, staticAvatarPath is the same as avatarPath
|
|
*
|
|
* avatarInProfile is the avatar as the user set it, once downloaded and stored in the application attachments folder.
|
|
*
|
|
* Note: if the user is Pro, but didn't set an animated avatar, `avatarInProfile` and `fallbackAvatarInProfile` will point to the same file
|
|
*/
|
|
avatarInProfile?: string;
|
|
/**
|
|
* This is the always static version of the avatar in profile.
|
|
* If the user has pro, avatarInProfile will be used (and so his avatar will be animated if it was already).
|
|
* If the user doesn't have pro, fallbackAvatarInProfile will be used, and the avatar will be displayed as a static image.
|
|
*
|
|
* Note: if the user is Pro, but didn't set an animated avatar, `avatarInProfile` and `fallbackAvatarInProfile` will point to the same file
|
|
*/
|
|
fallbackAvatarInProfile?: string;
|
|
|
|
isTrustedForAttachmentDownload: boolean; // not synced across devices, this field is used if we should auto download attachments from this conversation or not
|
|
|
|
conversationIdOrigin?: string; // The conversation from which this conversation originated from: blinded message request or 03-group admin who invited us
|
|
|
|
lastJoinedTimestamp: number; // GroupV2: last time we were added to this group, should eventually be removed to rely on libsession value directly
|
|
|
|
// ===========================================================================
|
|
// All of the items below are duplicated one way or the other with libsession.
|
|
// It would be nice to at some point be able to only rely on libsession dumps
|
|
// for those so there is no need to keep them in sync, but just have them in the dumps.
|
|
// Note: If we do remove them, we also need to add some logic to the wrappers. For instance, we can currently search by nickname or display name and that works through the DB.
|
|
|
|
displayNameInProfile?: string; // no matter the type of conversation, this is the real name as set by the user/name of the open or closed group
|
|
nickname?: string; // this is the name WE gave to that user (only applicable to private chats, not closed group neither opengroups)
|
|
profileKey?: string; // If set, this is a hex string.
|
|
|
|
/**
|
|
* This is the url of the avatar on the file server v2 or sogs server.
|
|
* We use this to detect if we need to re-download the avatar from someone/ a community.
|
|
*/
|
|
avatarPointer?: string;
|
|
/**
|
|
* This is the timestamp of the last time the profile of that user was updated.
|
|
* Only used for private chats (or blinded), but not for groups avatars nor communities.
|
|
* An incoming avatarPointer & profileKey will only be applied if the provided
|
|
* profileUpdatedSeconds is more recent than the currently stored one.
|
|
*/
|
|
profileUpdatedSeconds?: number;
|
|
|
|
/**
|
|
* Bitset of pro features that this user advertised in his last message.
|
|
* This field is only used for private chats (or blinded), but not for groups avatars nor communities.
|
|
* Note: this is dependent to `profileUpdatedSeconds` for updates, so it needs an incoming LokiProfile to be updated.
|
|
* This is a string as it is a stringified bigint.
|
|
* We use
|
|
* - a bigint so we can do bitset operations on it if need, and we are expected to support 64 pro features
|
|
* - a string as we need to convert a bigint to a string to send it over IPC.
|
|
*/
|
|
bitsetProFeatures?: string;
|
|
|
|
proGenIndexHashB64?: string;
|
|
proExpiryTsMs?: number;
|
|
|
|
triggerNotificationsFor: ConversationNotificationSettingType;
|
|
/** in seconds, 0 means no expiration */
|
|
expireTimer: number;
|
|
|
|
/**
|
|
* Members of 03-groups and legacy groups until we remove them entirely (not used for communities)
|
|
*/
|
|
members: Array<string>;
|
|
/**
|
|
* For sogs and closed group: the unique admins of that group
|
|
*/
|
|
groupAdmins: Array<string>;
|
|
|
|
/**
|
|
* -1 = hidden (contact and NTS only), 0 = normal, 1 = pinned
|
|
*/
|
|
priority: number;
|
|
|
|
isApproved: boolean; // if we sent a message request or sent a message to this contact, we approve them. If isApproved & didApproveMe, a message request becomes a contact
|
|
didApproveMe: boolean; // if our message request was approved already (or they've sent us a message request/message themselves). If isApproved & didApproveMe, a message request becomes a contact
|
|
|
|
markedAsUnread: boolean; // Force the conversation as unread even if all the messages are read. Used to highlight a conversation the user wants to check again later, synced.
|
|
|
|
blocksSogsMsgReqsTimestamp: number; // if the convo is blinded and the user has denied contact through sogs, this field be set to the user's latest message timestamp
|
|
|
|
/** disappearing messages setting for this conversation */
|
|
expirationMode: DisappearingMessageConversationModeType;
|
|
|
|
/**
|
|
* An 03-group is expired if an admin didn't come online for the last 30 days.
|
|
* In that case, we might not have any keys on the swarm, and so restoring from seed would mean we can't actually
|
|
* send any messages/nor decrypt any.
|
|
*/
|
|
isExpired03Group?: boolean;
|
|
}
|
|
|
|
/**
|
|
* This function mutates optAttributes
|
|
* @param optAttributes the entry object attributes to set the defaults to.
|
|
*
|
|
* Test are in ConversationModels_test.ts
|
|
*/
|
|
export const fillConvoAttributesWithDefaults = (
|
|
optAttributes: ConversationAttributes
|
|
): ConversationAttributes => {
|
|
return defaults(optAttributes, {
|
|
members: [],
|
|
groupAdmins: [],
|
|
|
|
lastJoinedTimestamp: 0,
|
|
expirationMode: 'off',
|
|
expireTimer: 0,
|
|
|
|
active_at: 0,
|
|
|
|
lastMessage: null,
|
|
lastMessageStatus: undefined,
|
|
lastMessageInteractionType: null,
|
|
lastMessageInteractionStatus: null,
|
|
|
|
bitsetProFeatures: undefined,
|
|
proGenIndexHashB64: undefined,
|
|
proExpiryTsMs: undefined,
|
|
|
|
triggerNotificationsFor: 'all', // if the settings is not set in the db, this is the default
|
|
|
|
isTrustedForAttachmentDownload: false, // we don't trust a contact until we say so
|
|
isApproved: false,
|
|
didApproveMe: false,
|
|
left: false,
|
|
priority: CONVERSATION_PRIORITIES.default,
|
|
markedAsUnread: false,
|
|
blocksSogsMsgReqsTimestamp: 0,
|
|
});
|
|
};
|
|
|
|
export const READ_MESSAGE_STATE = {
|
|
unread: 1,
|
|
read: 0,
|
|
} as const;
|
|
|
|
export enum ConvoTypeNarrow {
|
|
/**
|
|
* Our own conversation.
|
|
* Those details needs to be stored in libsession's nts config (UserProfile).
|
|
*/
|
|
nts = 'nts',
|
|
/**
|
|
* A blinded acquaintance is a user we are **not** chatting to directly (i.e. not approved nor didApproveMe),
|
|
* but they are blinded.
|
|
* This could be any user of a blinded community to which we have not sent a message request, and they did not either.
|
|
* Those are not saved in libsession currently.
|
|
*/
|
|
blindedAcquaintance = 'blindedAcquaintance',
|
|
/**
|
|
* A blinded contact is a user we have sent a message request through a blinded community.
|
|
* Those are not saved in libsession currently, but libsession could store them for us.
|
|
*/
|
|
blindedContact = 'blindedContact',
|
|
/**
|
|
* A non-blinded user we have not directly talk to, but through a group/(unblinded) community only.
|
|
* They could just be members of a group we are part of.
|
|
* Those are not saved in libsession's contact, but as group members in MetaGroup if we know them through a group.
|
|
* If we know them through a community, they are not saved in libsession at all currently..
|
|
*/
|
|
privateAcquaintance = 'privateAcquaintance',
|
|
/**
|
|
* This is a contact that we have approved, or they sent us a message request.
|
|
* We could be friends with them, if both flags are true.
|
|
* This contact must be stored in the contacts config.
|
|
*/
|
|
contact = 'contact',
|
|
/**
|
|
* This conversation is a community. It must be stored in the libsession's community config.
|
|
*/
|
|
community = 'community',
|
|
/**
|
|
* Those are legacy groups. i.e. private groups that start with 05.
|
|
*/
|
|
legacyGroup = 'legacyGroup',
|
|
/**
|
|
* Those are 03-groups. i.e. private groups that start with 03.
|
|
*/
|
|
group = 'group',
|
|
}
|
|
|
|
export type WithAvatarPointer = {
|
|
avatarPointer: string;
|
|
};
|
|
|
|
export type WithProfileUpdatedAtSeconds = {
|
|
/**
|
|
* 0 is allowed for the transition period (until enough users have migrated to sending their profileUpdatedAtSeconds).
|
|
* Allowed as in an incoming message with a lokiProfile updated at 0, will be applied locally, if needed
|
|
*/
|
|
profileUpdatedAtSeconds: number;
|
|
};
|
|
|
|
export type WithProfileKey = {
|
|
profileKey: Uint8Array | string;
|
|
};
|
|
|
|
export type WithAvatarPointerProfileKey = WithAvatarPointer & WithProfileKey;
|
|
|
|
export type WithAvatarPath = {
|
|
avatarPath: string;
|
|
};
|
|
|
|
export type WithFallbackAvatarPath = {
|
|
fallbackAvatarPath: string;
|
|
};
|
|
|
|
export type WithAvatarPathAndFallback = WithAvatarPath & WithFallbackAvatarPath;
|