275 lines
6.4 KiB
TypeScript

import { addReducer, getGlobal, setGlobal } from '../../../lib/teact/teactn';
import { callApi } from '../../../api/gramjs';
import * as mediaLoader from '../../../util/mediaLoader';
import { ApiAppConfig, ApiMediaFormat } from '../../../api/types';
import {
selectChat,
selectChatMessage,
selectDefaultReaction,
selectLocalAnimatedEmojiEffectByName,
} from '../../selectors';
import { addMessageReaction, subtractXForEmojiInteraction } from '../../reducers/reactions';
import { addUsers, updateChatMessage } from '../../reducers';
import { buildCollectionByKey, omit } from '../../../util/iteratees';
import { ANIMATION_LEVEL_MAX } from '../../../config';
addReducer('loadAvailableReactions', () => {
(async () => {
const result = await callApi('getAvailableReactions');
if (!result) {
return;
}
// Preload animations
result.forEach((availableReaction) => {
if (availableReaction.aroundAnimation) {
mediaLoader.fetch(`sticker${availableReaction.aroundAnimation.id}`, ApiMediaFormat.Lottie);
}
if (availableReaction.centerIcon) {
mediaLoader.fetch(`sticker${availableReaction.centerIcon.id}`, ApiMediaFormat.Lottie);
}
});
setGlobal({
...getGlobal(),
availableReactions: result,
});
})();
});
addReducer('interactWithAnimatedEmoji', (global, actions, payload) => {
const {
emoji, x, y, localEffect, startSize, isReversed,
} = payload!;
return {
...global,
activeEmojiInteraction: {
animatedEffect: emoji || localEffect,
x: subtractXForEmojiInteraction(global, x),
y,
startSize,
isReversed,
},
};
});
addReducer('sendEmojiInteraction', (global, actions, payload) => {
const {
messageId, chatId, emoji, interactions, localEffect,
x, y, startX, startY, startSize,
} = payload!;
const chat = selectChat(global, chatId);
if (!chat || (!emoji && !localEffect) || chatId === global.currentUserId) {
return undefined;
}
void callApi('sendEmojiInteraction', {
chat,
messageId,
emoticon: emoji || selectLocalAnimatedEmojiEffectByName(localEffect),
timestamps: interactions,
});
if (!global.activeEmojiInteraction) return undefined;
return {
...global,
activeEmojiInteraction: {
...global.activeEmojiInteraction,
endX: subtractXForEmojiInteraction(global, x),
endY: y,
...(startX && { x: subtractXForEmojiInteraction(global, startX) }),
...(startY && { y: startY }),
...(startSize && { startSize }),
},
};
});
addReducer('sendDefaultReaction', (global, actions, payload) => {
const {
chatId, messageId, x, y,
} = payload;
const reaction = selectDefaultReaction(global, chatId);
if (!reaction) return;
actions.sendReaction({
chatId,
messageId,
reaction,
x,
y,
});
});
addReducer('sendReaction', (global, actions, payload) => {
const {
chatId, messageId,
}: { messageId: number; chatId: string } = payload;
let { reaction } = payload;
const chat = selectChat(global, chatId);
const message = selectChatMessage(global, chatId, messageId);
if (!chat || !message) {
return undefined;
}
if (message.reactions?.results?.some((l) => l.reaction === reaction && l.isChosen)) {
reaction = undefined;
}
void callApi('sendReaction', { chat, messageId, reaction });
const { animationLevel } = global.settings.byKey;
if (animationLevel === ANIMATION_LEVEL_MAX) {
global = {
...global,
activeReactions: {
...(reaction ? global.activeReactions : omit(global.activeReactions, [messageId])),
...(reaction && {
[messageId]: {
reaction,
messageId,
},
}),
},
};
}
return addMessageReaction(global, chatId, messageId, reaction);
});
addReducer('openChat', (global) => {
return {
...global,
activeReactions: {},
};
});
addReducer('stopActiveReaction', (global, actions, payload) => {
const { messageId, reaction } = payload;
if (global.activeReactions[messageId]?.reaction !== reaction) {
return global;
}
return {
...global,
activeReactions: omit(global.activeReactions, [messageId]),
};
});
addReducer('setDefaultReaction', (global, actions, payload) => {
const { reaction } = payload;
(async () => {
const result = await callApi('setDefaultReaction', { reaction });
if (!result) {
return;
}
global = getGlobal();
setGlobal({
...global,
appConfig: {
...global.appConfig,
defaultReaction: reaction,
} as ApiAppConfig,
});
})();
});
addReducer('stopActiveEmojiInteraction', (global) => {
return {
...global,
activeEmojiInteraction: undefined,
};
});
addReducer('loadReactors', (global, actions, payload) => {
const { chatId, messageId, reaction } = payload;
const chat = selectChat(global, chatId);
const message = selectChatMessage(global, chatId, messageId);
if (!chat || !message) {
return;
}
const offset = message.reactors?.nextOffset;
(async () => {
const result = await callApi('fetchMessageReactionsList', {
reaction,
chat,
messageId,
offset,
});
if (!result) {
return;
}
global = getGlobal();
if (result.users?.length) {
global = addUsers(global, buildCollectionByKey(result.users, 'id'));
}
const { nextOffset, count, reactions } = result;
setGlobal(updateChatMessage(global, chatId, messageId, {
reactors: {
nextOffset,
count,
reactions: [
...(message.reactors?.reactions || []),
...reactions,
],
},
}));
})();
});
addReducer('loadMessageReactions', (global, actions, payload) => {
const { ids, chatId } = payload;
const chat = selectChat(global, chatId);
if (!chat) {
return;
}
callApi('fetchMessageReactions', { ids, chat });
});
addReducer('sendWatchingEmojiInteraction', (global, actions, payload) => {
const {
chatId, emoticon, x, y, startSize, isReversed,
} = payload;
const chat = selectChat(global, chatId);
if (!chat || !global.activeEmojiInteraction || chatId === global.currentUserId) {
return undefined;
}
callApi('sendWatchingEmojiInteraction', { chat, emoticon });
return {
...global,
activeEmojiInteraction: {
...global.activeEmojiInteraction,
x: subtractXForEmojiInteraction(global, x),
y,
startSize,
isReversed,
},
};
});