527 lines
12 KiB
TypeScript
527 lines
12 KiB
TypeScript
import { addActionHandler, getGlobal, setGlobal } from '../../index';
|
|
|
|
import type { ApiError, ApiNotification } from '../../../api/types';
|
|
import { MAIN_THREAD_ID } from '../../../api/types';
|
|
|
|
import { APP_VERSION, DEBUG, GLOBAL_STATE_CACHE_CUSTOM_EMOJI_LIMIT } from '../../../config';
|
|
import getReadableErrorText from '../../../util/getReadableErrorText';
|
|
import {
|
|
selectChatMessage, selectCurrentChat, selectCurrentMessageList, selectIsTrustedBot,
|
|
} from '../../selectors';
|
|
import generateIdFor from '../../../util/generateIdFor';
|
|
import { unique } from '../../../util/iteratees';
|
|
import { getIsMobile, getIsTablet } from '../../../hooks/useAppLayout';
|
|
|
|
export const APP_VERSION_URL = 'version.txt';
|
|
const MAX_STORED_EMOJIS = 8 * 4; // Represents four rows of recent emojis
|
|
|
|
addActionHandler('toggleChatInfo', (global, action, payload) => {
|
|
return {
|
|
...global,
|
|
isChatInfoShown: payload !== undefined ? payload : !global.isChatInfoShown,
|
|
};
|
|
});
|
|
|
|
addActionHandler('setLeftColumnWidth', (global, actions, payload) => {
|
|
const leftColumnWidth = payload;
|
|
|
|
return {
|
|
...global,
|
|
leftColumnWidth,
|
|
};
|
|
});
|
|
|
|
addActionHandler('resetLeftColumnWidth', (global) => {
|
|
return {
|
|
...global,
|
|
leftColumnWidth: undefined,
|
|
};
|
|
});
|
|
|
|
addActionHandler('toggleManagement', (global) => {
|
|
const { chatId } = selectCurrentMessageList(global) || {};
|
|
|
|
if (!chatId) {
|
|
return undefined;
|
|
}
|
|
|
|
return {
|
|
...global,
|
|
management: {
|
|
byChatId: {
|
|
...global.management.byChatId,
|
|
[chatId]: {
|
|
...global.management.byChatId[chatId],
|
|
isActive: !(global.management.byChatId[chatId] || {}).isActive,
|
|
},
|
|
},
|
|
},
|
|
};
|
|
});
|
|
|
|
addActionHandler('requestNextManagementScreen', (global, actions, payload) => {
|
|
const { screen } = payload || {};
|
|
const { chatId } = selectCurrentMessageList(global) || {};
|
|
|
|
if (!chatId) {
|
|
return undefined;
|
|
}
|
|
|
|
return {
|
|
...global,
|
|
management: {
|
|
byChatId: {
|
|
...global.management.byChatId,
|
|
[chatId]: {
|
|
...global.management.byChatId[chatId],
|
|
isActive: true,
|
|
nextScreen: screen,
|
|
},
|
|
},
|
|
},
|
|
};
|
|
});
|
|
|
|
addActionHandler('closeManagement', (global) => {
|
|
const { chatId } = selectCurrentMessageList(global) || {};
|
|
|
|
if (!chatId) {
|
|
return undefined;
|
|
}
|
|
|
|
return {
|
|
...global,
|
|
management: {
|
|
byChatId: {
|
|
...global.management.byChatId,
|
|
[chatId]: {
|
|
...global.management.byChatId[chatId],
|
|
isActive: false,
|
|
},
|
|
},
|
|
},
|
|
};
|
|
});
|
|
|
|
addActionHandler('openChat', (global) => {
|
|
if (!getIsMobile() && !getIsTablet()) {
|
|
return undefined;
|
|
}
|
|
|
|
return {
|
|
...global,
|
|
isLeftColumnShown: global.messages.messageLists.length === 0,
|
|
};
|
|
});
|
|
|
|
addActionHandler('toggleStatistics', (global) => {
|
|
return {
|
|
...global,
|
|
isStatisticsShown: !global.isStatisticsShown,
|
|
statistics: {
|
|
...global.statistics,
|
|
currentMessageId: undefined,
|
|
},
|
|
};
|
|
});
|
|
|
|
addActionHandler('toggleMessageStatistics', (global, action, payload) => {
|
|
return {
|
|
...global,
|
|
statistics: {
|
|
...global.statistics,
|
|
currentMessageId: payload?.messageId,
|
|
},
|
|
};
|
|
});
|
|
|
|
addActionHandler('toggleLeftColumn', (global) => {
|
|
return {
|
|
...global,
|
|
isLeftColumnShown: !global.isLeftColumnShown,
|
|
};
|
|
});
|
|
|
|
addActionHandler('addRecentEmoji', (global, action, payload) => {
|
|
const { emoji } = payload;
|
|
const { recentEmojis } = global;
|
|
if (!recentEmojis) {
|
|
return {
|
|
...global,
|
|
recentEmojis: [emoji],
|
|
};
|
|
}
|
|
|
|
const newEmojis = recentEmojis.filter((e) => e !== emoji);
|
|
newEmojis.unshift(emoji);
|
|
if (newEmojis.length > MAX_STORED_EMOJIS) {
|
|
newEmojis.pop();
|
|
}
|
|
|
|
return {
|
|
...global,
|
|
recentEmojis: newEmojis,
|
|
};
|
|
});
|
|
|
|
addActionHandler('addRecentSticker', (global, action, payload) => {
|
|
const { sticker } = payload;
|
|
const { recent } = global.stickers;
|
|
if (!recent) {
|
|
return {
|
|
...global,
|
|
stickers: {
|
|
...global.stickers,
|
|
recent: {
|
|
hash: '0',
|
|
stickers: [sticker],
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
const newStickers = recent.stickers.filter((s) => s.id !== sticker.id);
|
|
newStickers.unshift(sticker);
|
|
|
|
return {
|
|
...global,
|
|
stickers: {
|
|
...global.stickers,
|
|
recent: {
|
|
...recent,
|
|
stickers: newStickers,
|
|
},
|
|
},
|
|
};
|
|
});
|
|
|
|
addActionHandler('addRecentCustomEmoji', (global, action, payload) => {
|
|
const { documentId } = payload;
|
|
const { recentCustomEmojis } = global;
|
|
if (!recentCustomEmojis) {
|
|
return {
|
|
...global,
|
|
recentCustomEmojis: [documentId],
|
|
};
|
|
}
|
|
|
|
const newEmojis = recentCustomEmojis.filter((id) => id !== documentId);
|
|
newEmojis.unshift(documentId);
|
|
if (newEmojis.length > MAX_STORED_EMOJIS) {
|
|
newEmojis.pop();
|
|
}
|
|
|
|
return {
|
|
...global,
|
|
recentCustomEmojis: newEmojis,
|
|
};
|
|
});
|
|
|
|
addActionHandler('clearRecentCustomEmoji', (global) => {
|
|
return {
|
|
...global,
|
|
recentCustomEmojis: [],
|
|
};
|
|
});
|
|
|
|
addActionHandler('reorderStickerSets', (global, action, payload) => {
|
|
const { order, isCustomEmoji } = payload;
|
|
return {
|
|
...global,
|
|
stickers: {
|
|
...global.stickers,
|
|
added: {
|
|
setIds: (!isCustomEmoji ? order : global.stickers.added.setIds),
|
|
},
|
|
},
|
|
customEmojis: {
|
|
...global.customEmojis,
|
|
added: {
|
|
setIds: (isCustomEmoji ? order : global.customEmojis.added.setIds),
|
|
},
|
|
},
|
|
};
|
|
});
|
|
|
|
addActionHandler('showNotification', (global, actions, payload) => {
|
|
const notification = payload!;
|
|
notification.localId = generateIdFor({});
|
|
|
|
const newNotifications = [...global.notifications];
|
|
const existingNotificationIndex = newNotifications.findIndex((n) => n.message === notification.message);
|
|
if (existingNotificationIndex !== -1) {
|
|
newNotifications.splice(existingNotificationIndex, 1);
|
|
}
|
|
|
|
newNotifications.push(notification as ApiNotification);
|
|
|
|
return {
|
|
...global,
|
|
notifications: newNotifications,
|
|
};
|
|
});
|
|
|
|
addActionHandler('dismissNotification', (global, actions, payload) => {
|
|
const newNotifications = global.notifications.filter(({ localId }) => localId !== payload.localId);
|
|
|
|
return {
|
|
...global,
|
|
notifications: newNotifications,
|
|
};
|
|
});
|
|
|
|
addActionHandler('showDialog', (global, actions, payload) => {
|
|
const { data } = payload!;
|
|
|
|
// Filter out errors that we don't want to show to the user
|
|
if ('message' in data && data.hasErrorKey && !getReadableErrorText(data)) {
|
|
return global;
|
|
}
|
|
|
|
const newDialogs = [...global.dialogs];
|
|
if ('message' in data) {
|
|
const existingErrorIndex = newDialogs.findIndex((err) => (err as ApiError).message === data.message);
|
|
if (existingErrorIndex !== -1) {
|
|
newDialogs.splice(existingErrorIndex, 1);
|
|
}
|
|
}
|
|
|
|
newDialogs.push(data);
|
|
|
|
return {
|
|
...global,
|
|
dialogs: newDialogs,
|
|
};
|
|
});
|
|
|
|
addActionHandler('dismissDialog', (global) => {
|
|
const newDialogs = [...global.dialogs];
|
|
|
|
newDialogs.pop();
|
|
|
|
return {
|
|
...global,
|
|
dialogs: newDialogs,
|
|
};
|
|
});
|
|
|
|
addActionHandler('toggleSafeLinkModal', (global, actions, payload) => {
|
|
const { url: safeLinkModalUrl } = payload;
|
|
|
|
return {
|
|
...global,
|
|
safeLinkModalUrl,
|
|
};
|
|
});
|
|
|
|
addActionHandler('openHistoryCalendar', (global, actions, payload) => {
|
|
const { selectedAt } = payload;
|
|
|
|
return {
|
|
...global,
|
|
historyCalendarSelectedAt: selectedAt,
|
|
};
|
|
});
|
|
|
|
addActionHandler('closeHistoryCalendar', (global) => {
|
|
return {
|
|
...global,
|
|
historyCalendarSelectedAt: undefined,
|
|
};
|
|
});
|
|
|
|
addActionHandler('openGame', (global, actions, payload) => {
|
|
const { url, chatId, messageId } = payload;
|
|
|
|
const message = selectChatMessage(global, chatId, messageId);
|
|
if (!message) return;
|
|
|
|
const botId = message.viaBotId || message.senderId;
|
|
if (!botId) return;
|
|
|
|
if (!selectIsTrustedBot(global, botId)) {
|
|
setGlobal({
|
|
...global,
|
|
botTrustRequest: {
|
|
botId,
|
|
type: 'game',
|
|
onConfirm: {
|
|
action: 'openGame',
|
|
payload,
|
|
},
|
|
},
|
|
});
|
|
return;
|
|
}
|
|
|
|
setGlobal({
|
|
...global,
|
|
openedGame: {
|
|
url,
|
|
chatId,
|
|
messageId,
|
|
},
|
|
});
|
|
});
|
|
|
|
addActionHandler('closeGame', (global) => {
|
|
return {
|
|
...global,
|
|
openedGame: undefined,
|
|
};
|
|
});
|
|
|
|
addActionHandler('requestConfetti', (global, actions, payload) => {
|
|
const {
|
|
top, left, width, height,
|
|
} = payload || {};
|
|
const { animationLevel } = global.settings.byKey;
|
|
if (animationLevel === 0) return undefined;
|
|
|
|
return {
|
|
...global,
|
|
confetti: {
|
|
lastConfettiTime: Date.now(),
|
|
top,
|
|
left,
|
|
width,
|
|
height,
|
|
},
|
|
};
|
|
});
|
|
|
|
addActionHandler('updateAttachmentSettings', (global, actions, payload) => {
|
|
const {
|
|
shouldCompress, shouldSendGrouped,
|
|
} = payload;
|
|
|
|
return {
|
|
...global,
|
|
attachmentSettings: {
|
|
shouldCompress: shouldCompress ?? global.attachmentSettings.shouldCompress,
|
|
shouldSendGrouped: shouldSendGrouped ?? global.attachmentSettings.shouldSendGrouped,
|
|
},
|
|
};
|
|
});
|
|
|
|
addActionHandler('openLimitReachedModal', (global, actions, payload) => {
|
|
const { limit } = payload;
|
|
|
|
return {
|
|
...global,
|
|
limitReachedModal: {
|
|
limit,
|
|
},
|
|
};
|
|
});
|
|
|
|
addActionHandler('closeLimitReachedModal', (global) => {
|
|
return {
|
|
...global,
|
|
limitReachedModal: undefined,
|
|
};
|
|
});
|
|
|
|
addActionHandler('closeStickerSetModal', (global) => {
|
|
return {
|
|
...global,
|
|
openedStickerSetShortName: undefined,
|
|
};
|
|
});
|
|
|
|
addActionHandler('openCustomEmojiSets', (global, actions, payload) => {
|
|
const { setIds } = payload;
|
|
return {
|
|
...global,
|
|
openedCustomEmojiSetIds: setIds,
|
|
};
|
|
});
|
|
|
|
addActionHandler('closeCustomEmojiSets', (global) => {
|
|
return {
|
|
...global,
|
|
openedCustomEmojiSetIds: undefined,
|
|
};
|
|
});
|
|
|
|
addActionHandler('updateLastRenderedCustomEmojis', (global, actions, payload) => {
|
|
const { ids } = payload;
|
|
const { lastRendered } = global.customEmojis;
|
|
|
|
return {
|
|
...global,
|
|
customEmojis: {
|
|
...global.customEmojis,
|
|
lastRendered: unique([...lastRendered, ...ids]).slice(0, GLOBAL_STATE_CACHE_CUSTOM_EMOJI_LIMIT),
|
|
},
|
|
};
|
|
});
|
|
|
|
addActionHandler('openCreateTopicPanel', (global, actions, payload) => {
|
|
const { chatId } = payload;
|
|
|
|
// Topic panel can be opened only if there is a selected chat
|
|
const currentChat = selectCurrentChat(global);
|
|
if (!currentChat) actions.openChat({ id: chatId, threadId: MAIN_THREAD_ID });
|
|
|
|
return {
|
|
...global,
|
|
createTopicPanel: {
|
|
chatId,
|
|
},
|
|
};
|
|
});
|
|
|
|
addActionHandler('closeCreateTopicPanel', (global) => {
|
|
return {
|
|
...global,
|
|
createTopicPanel: undefined,
|
|
};
|
|
});
|
|
|
|
addActionHandler('openEditTopicPanel', (global, actions, payload) => {
|
|
const { chatId, topicId } = payload;
|
|
|
|
// Topic panel can be opened only if there is a selected chat
|
|
const currentChat = selectCurrentChat(global);
|
|
if (!currentChat) actions.openChat({ id: chatId });
|
|
|
|
return {
|
|
...global,
|
|
editTopicPanel: {
|
|
chatId,
|
|
topicId,
|
|
},
|
|
};
|
|
});
|
|
|
|
addActionHandler('closeEditTopicPanel', (global) => {
|
|
return {
|
|
...global,
|
|
editTopicPanel: undefined,
|
|
};
|
|
});
|
|
|
|
addActionHandler('checkAppVersion', () => {
|
|
const APP_VERSION_REGEX = /^\d+\.\d+(\.\d+)?$/;
|
|
|
|
fetch(`${APP_VERSION_URL}?${Date.now()}`)
|
|
.then((response) => response.text())
|
|
.then((version) => {
|
|
version = version.trim();
|
|
|
|
if (APP_VERSION_REGEX.test(version) && version !== APP_VERSION) {
|
|
setGlobal({
|
|
...getGlobal(),
|
|
isUpdateAvailable: true,
|
|
});
|
|
}
|
|
})
|
|
.catch((err) => {
|
|
if (DEBUG) {
|
|
// eslint-disable-next-line no-console
|
|
console.error('[checkAppVersion failed] ', err);
|
|
}
|
|
});
|
|
});
|