Profile: Infinite scroll for members
This commit is contained in:
parent
1984318297
commit
e454abd4f3
@ -12,7 +12,7 @@ import {
|
|||||||
ApiChatAdminRights,
|
ApiChatAdminRights,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
|
|
||||||
import { DEBUG, ARCHIVED_FOLDER_ID, CHANNEL_MEMBERS_LIMIT } from '../../../config';
|
import { DEBUG, ARCHIVED_FOLDER_ID, MEMBERS_LOAD_SLICE } from '../../../config';
|
||||||
import { invokeRequest, uploadFile } from './client';
|
import { invokeRequest, uploadFile } from './client';
|
||||||
import {
|
import {
|
||||||
buildApiChatFromDialog,
|
buildApiChatFromDialog,
|
||||||
@ -156,11 +156,12 @@ export async function fetchChats({
|
|||||||
|
|
||||||
export function fetchFullChat(chat: ApiChat) {
|
export function fetchFullChat(chat: ApiChat) {
|
||||||
const { id, accessHash, adminRights } = chat;
|
const { id, accessHash, adminRights } = chat;
|
||||||
|
|
||||||
const input = buildInputEntity(id, accessHash);
|
const input = buildInputEntity(id, accessHash);
|
||||||
|
|
||||||
return input instanceof GramJs.InputChannel
|
return input instanceof GramJs.InputChannel
|
||||||
? getFullChannelInfo(input, adminRights)
|
? getFullChannelInfo(id, accessHash!, adminRights)
|
||||||
: getFullChatInfo(input as number);
|
: getFullChatInfo(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function searchChats({ query }: { query: string }) {
|
export async function searchChats({ query }: { query: string }) {
|
||||||
@ -298,7 +299,9 @@ async function getFullChatInfo(chatId: number): Promise<{
|
|||||||
fullInfo: ApiChatFullInfo;
|
fullInfo: ApiChatFullInfo;
|
||||||
users?: ApiUser[];
|
users?: ApiUser[];
|
||||||
} | undefined> {
|
} | undefined> {
|
||||||
const result = await invokeRequest(new GramJs.messages.GetFullChat({ chatId }));
|
const result = await invokeRequest(new GramJs.messages.GetFullChat({
|
||||||
|
chatId: buildInputEntity(chatId) as number,
|
||||||
|
}));
|
||||||
|
|
||||||
if (!result || !(result.fullChat instanceof GramJs.ChatFull)) {
|
if (!result || !(result.fullChat instanceof GramJs.ChatFull)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -328,10 +331,13 @@ async function getFullChatInfo(chatId: number): Promise<{
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getFullChannelInfo(
|
async function getFullChannelInfo(
|
||||||
channel: GramJs.InputChannel,
|
id: number,
|
||||||
|
accessHash: string,
|
||||||
adminRights?: ApiChatAdminRights,
|
adminRights?: ApiChatAdminRights,
|
||||||
) {
|
) {
|
||||||
const result = await invokeRequest(new GramJs.channels.GetFullChannel({ channel }));
|
const result = await invokeRequest(new GramJs.channels.GetFullChannel({
|
||||||
|
channel: buildInputEntity(id, accessHash) as GramJs.InputChannel,
|
||||||
|
}));
|
||||||
|
|
||||||
if (!result || !(result.fullChat instanceof GramJs.ChannelFull)) {
|
if (!result || !(result.fullChat instanceof GramJs.ChannelFull)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -354,12 +360,12 @@ async function getFullChannelInfo(
|
|||||||
? exportedInvite.link
|
? exportedInvite.link
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const { members, users } = (canViewParticipants && await getChannelMembers(channel)) || {};
|
const { members, users } = (canViewParticipants && await fetchMembers(id, accessHash)) || {};
|
||||||
const { members: kickedMembers, users: bannedUsers } = (
|
const { members: kickedMembers, users: bannedUsers } = (
|
||||||
canViewParticipants && adminRights && await getChannelMembers(channel, 'kicked')
|
canViewParticipants && adminRights && await fetchMembers(id, accessHash, 'kicked')
|
||||||
) || {};
|
) || {};
|
||||||
const { members: adminMembers, users: adminUsers } = (
|
const { members: adminMembers, users: adminUsers } = (
|
||||||
canViewParticipants && adminRights && await getChannelMembers(channel, 'admin')
|
canViewParticipants && adminRights && await fetchMembers(id, accessHash, 'admin')
|
||||||
) || {};
|
) || {};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -785,9 +791,11 @@ export function toggleSignatures({
|
|||||||
|
|
||||||
type ChannelMembersFilter = 'kicked' | 'admin' | 'recent';
|
type ChannelMembersFilter = 'kicked' | 'admin' | 'recent';
|
||||||
|
|
||||||
async function getChannelMembers(
|
export async function fetchMembers(
|
||||||
channel: GramJs.InputChannel,
|
chatId: number,
|
||||||
|
accessHash: string,
|
||||||
memberFilter: ChannelMembersFilter = 'recent',
|
memberFilter: ChannelMembersFilter = 'recent',
|
||||||
|
offset?: number,
|
||||||
) {
|
) {
|
||||||
let filter: GramJs.TypeChannelParticipantsFilter;
|
let filter: GramJs.TypeChannelParticipantsFilter;
|
||||||
|
|
||||||
@ -804,9 +812,10 @@ async function getChannelMembers(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = await invokeRequest(new GramJs.channels.GetParticipants({
|
const result = await invokeRequest(new GramJs.channels.GetParticipants({
|
||||||
channel,
|
channel: buildInputEntity(chatId, accessHash) as GramJs.InputChannel,
|
||||||
filter,
|
filter,
|
||||||
limit: CHANNEL_MEMBERS_LIMIT,
|
offset,
|
||||||
|
limit: MEMBERS_LOAD_SLICE,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (!result || result instanceof GramJs.channels.ChannelParticipantsNotModified) {
|
if (!result || result instanceof GramJs.channels.ChannelParticipantsNotModified) {
|
||||||
|
|||||||
@ -14,7 +14,7 @@ export {
|
|||||||
fetchChatFolders, editChatFolder, deleteChatFolder, fetchRecommendedChatFolders,
|
fetchChatFolders, editChatFolder, deleteChatFolder, fetchRecommendedChatFolders,
|
||||||
getChatByUsername, togglePreHistoryHidden, updateChatDefaultBannedRights, updateChatMemberBannedRights,
|
getChatByUsername, togglePreHistoryHidden, updateChatDefaultBannedRights, updateChatMemberBannedRights,
|
||||||
updateChatTitle, updateChatAbout, toggleSignatures, updateChatAdmin, fetchGroupsForDiscussion, setDiscussionGroup,
|
updateChatTitle, updateChatAbout, toggleSignatures, updateChatAdmin, fetchGroupsForDiscussion, setDiscussionGroup,
|
||||||
migrateChat, openChatByInvite,
|
migrateChat, openChatByInvite, fetchMembers,
|
||||||
} from './chats';
|
} from './chats';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|||||||
@ -14,10 +14,10 @@ import {
|
|||||||
MediaViewerOrigin, ProfileState, ProfileTabType, SharedMediaType,
|
MediaViewerOrigin, ProfileState, ProfileTabType, SharedMediaType,
|
||||||
} from '../../types';
|
} from '../../types';
|
||||||
|
|
||||||
import { SHARED_MEDIA_SLICE, SLIDE_TRANSITION_DURATION } from '../../config';
|
import { MEMBERS_SLICE, SHARED_MEDIA_SLICE, SLIDE_TRANSITION_DURATION } from '../../config';
|
||||||
import { IS_TOUCH_ENV } from '../../util/environment';
|
import { IS_TOUCH_ENV } from '../../util/environment';
|
||||||
import {
|
import {
|
||||||
isChatAdmin, isChatChannel, isChatGroup, isChatPrivate,
|
isChatAdmin, isChatBasicGroup, isChatChannel, isChatGroup, isChatPrivate,
|
||||||
} from '../../modules/helpers';
|
} from '../../modules/helpers';
|
||||||
import {
|
import {
|
||||||
selectChatMessages,
|
selectChatMessages,
|
||||||
@ -57,6 +57,7 @@ type OwnProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type StateProps = {
|
type StateProps = {
|
||||||
|
isBasicGroup?: boolean;
|
||||||
isChannel?: boolean;
|
isChannel?: boolean;
|
||||||
resolvedUserId?: number;
|
resolvedUserId?: number;
|
||||||
chatMessages?: Record<number, ApiMessage>;
|
chatMessages?: Record<number, ApiMessage>;
|
||||||
@ -72,7 +73,7 @@ type StateProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
type DispatchProps = Pick<GlobalActions, (
|
type DispatchProps = Pick<GlobalActions, (
|
||||||
'setLocalMediaSearchType' | 'searchMediaMessagesLocal' | 'openMediaViewer' |
|
'setLocalMediaSearchType' | 'loadMoreMembers' | 'searchMediaMessagesLocal' | 'openMediaViewer' |
|
||||||
'openAudioPlayer' | 'openUserInfo' | 'focusMessage' | 'loadProfilePhotos'
|
'openAudioPlayer' | 'openUserInfo' | 'focusMessage' | 'loadProfilePhotos'
|
||||||
)>;
|
)>;
|
||||||
|
|
||||||
@ -89,6 +90,7 @@ const Profile: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
chatId,
|
chatId,
|
||||||
profileState,
|
profileState,
|
||||||
onProfileStateChange,
|
onProfileStateChange,
|
||||||
|
isBasicGroup,
|
||||||
isChannel,
|
isChannel,
|
||||||
resolvedUserId,
|
resolvedUserId,
|
||||||
chatMessages,
|
chatMessages,
|
||||||
@ -102,6 +104,7 @@ const Profile: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
isRestricted,
|
isRestricted,
|
||||||
lastSyncTime,
|
lastSyncTime,
|
||||||
setLocalMediaSearchType,
|
setLocalMediaSearchType,
|
||||||
|
loadMoreMembers,
|
||||||
searchMediaMessagesLocal,
|
searchMediaMessagesLocal,
|
||||||
openMediaViewer,
|
openMediaViewer,
|
||||||
openAudioPlayer,
|
openAudioPlayer,
|
||||||
@ -125,7 +128,7 @@ const Profile: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
const tabType = tabs[activeTab].type as ProfileTabType;
|
const tabType = tabs[activeTab].type as ProfileTabType;
|
||||||
|
|
||||||
const [resultType, viewportIds, getMore, noProfileInfo] = useProfileViewportIds(
|
const [resultType, viewportIds, getMore, noProfileInfo] = useProfileViewportIds(
|
||||||
isRightColumnShown, searchMediaMessagesLocal, tabType, mediaSearchType, members,
|
isRightColumnShown, loadMoreMembers, searchMediaMessagesLocal, tabType, mediaSearchType, members,
|
||||||
usersById, chatMessages, foundIds, chatId, lastSyncTime,
|
usersById, chatMessages, foundIds, chatId, lastSyncTime,
|
||||||
);
|
);
|
||||||
const activeKey = tabs.findIndex(({ type }) => type === resultType);
|
const activeKey = tabs.findIndex(({ type }) => type === resultType);
|
||||||
@ -306,8 +309,9 @@ const Profile: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
itemSelector={buildInfiniteScrollItemSelector(resultType)}
|
itemSelector={buildInfiniteScrollItemSelector(resultType)}
|
||||||
items={viewportIds}
|
items={viewportIds}
|
||||||
cacheBuster={cacheBuster}
|
cacheBuster={cacheBuster}
|
||||||
preloadBackwards={SHARED_MEDIA_SLICE}
|
sensitiveArea={500}
|
||||||
isDisabled={tabType === 'members'}
|
preloadBackwards={resultType === 'members' ? MEMBERS_SLICE : SHARED_MEDIA_SLICE}
|
||||||
|
isDisabled={resultType === 'members' && isBasicGroup}
|
||||||
noFastList
|
noFastList
|
||||||
onLoadMore={getMore}
|
onLoadMore={getMore}
|
||||||
onScroll={handleScroll}
|
onScroll={handleScroll}
|
||||||
@ -366,6 +370,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
const { byId: usersById } = global.users;
|
const { byId: usersById } = global.users;
|
||||||
|
|
||||||
const isGroup = chat && isChatGroup(chat);
|
const isGroup = chat && isChatGroup(chat);
|
||||||
|
const isBasicGroup = chat && isChatBasicGroup(chat);
|
||||||
const isChannel = chat && isChatChannel(chat);
|
const isChannel = chat && isChatChannel(chat);
|
||||||
const hasMembersTab = isGroup || (isChannel && isChatAdmin(chat!));
|
const hasMembersTab = isGroup || (isChannel && isChatAdmin(chat!));
|
||||||
const members = chat && chat.fullInfo && chat.fullInfo.members;
|
const members = chat && chat.fullInfo && chat.fullInfo.members;
|
||||||
@ -379,6 +384,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
isBasicGroup,
|
||||||
isChannel,
|
isChannel,
|
||||||
resolvedUserId,
|
resolvedUserId,
|
||||||
chatMessages,
|
chatMessages,
|
||||||
@ -397,6 +403,7 @@ export default memo(withGlobal<OwnProps>(
|
|||||||
},
|
},
|
||||||
(setGlobal, actions): DispatchProps => pick(actions, [
|
(setGlobal, actions): DispatchProps => pick(actions, [
|
||||||
'setLocalMediaSearchType',
|
'setLocalMediaSearchType',
|
||||||
|
'loadMoreMembers',
|
||||||
'searchMediaMessagesLocal',
|
'searchMediaMessagesLocal',
|
||||||
'openMediaViewer',
|
'openMediaViewer',
|
||||||
'openAudioPlayer',
|
'openAudioPlayer',
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
// @optimization
|
// @optimization
|
||||||
&:not(:hover) {
|
&:not(:hover) {
|
||||||
.Picker .chat-item-clickable:nth-child(n + 18) {
|
.chat-item-clickable:nth-child(n + 18) {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,13 +3,14 @@ import { useMemo, useRef } from '../../../lib/teact/teact';
|
|||||||
import { ApiChatMember, ApiMessage, ApiUser } from '../../../api/types';
|
import { ApiChatMember, ApiMessage, ApiUser } from '../../../api/types';
|
||||||
import { ProfileTabType, SharedMediaType } from '../../../types';
|
import { ProfileTabType, SharedMediaType } from '../../../types';
|
||||||
|
|
||||||
import { MESSAGE_SEARCH_SLICE, SHARED_MEDIA_SLICE } from '../../../config';
|
import { MEMBERS_SLICE, MESSAGE_SEARCH_SLICE, SHARED_MEDIA_SLICE } from '../../../config';
|
||||||
import { getMessageContentIds, sortUserIds } from '../../../modules/helpers';
|
import { getMessageContentIds, sortUserIds } from '../../../modules/helpers';
|
||||||
import useOnChange from '../../../hooks/useOnChange';
|
import useOnChange from '../../../hooks/useOnChange';
|
||||||
import useInfiniteScroll from '../../../hooks/useInfiniteScroll';
|
import useInfiniteScroll from '../../../hooks/useInfiniteScroll';
|
||||||
|
|
||||||
export default function useProfileViewportIds(
|
export default function useProfileViewportIds(
|
||||||
isRightColumnShown: boolean,
|
isRightColumnShown: boolean,
|
||||||
|
loadMoreMembers: AnyToVoidFunction,
|
||||||
searchMessages: AnyToVoidFunction,
|
searchMessages: AnyToVoidFunction,
|
||||||
tabType: ProfileTabType,
|
tabType: ProfileTabType,
|
||||||
mediaSearchType?: SharedMediaType,
|
mediaSearchType?: SharedMediaType,
|
||||||
@ -30,6 +31,10 @@ export default function useProfileViewportIds(
|
|||||||
return sortUserIds(groupChatMembers.map(({ userId }) => userId), usersById);
|
return sortUserIds(groupChatMembers.map(({ userId }) => userId), usersById);
|
||||||
}, [groupChatMembers, usersById]);
|
}, [groupChatMembers, usersById]);
|
||||||
|
|
||||||
|
const [memberViewportIds, getMoreMembers, noProfileInfoForMembers] = useInfiniteScrollForMembers(
|
||||||
|
resultType, loadMoreMembers, lastSyncTime, memberIds,
|
||||||
|
);
|
||||||
|
|
||||||
const [mediaViewportIds, getMoreMedia, noProfileInfoForMedia] = useInfiniteScrollForSharedMedia(
|
const [mediaViewportIds, getMoreMedia, noProfileInfoForMedia] = useInfiniteScrollForSharedMedia(
|
||||||
'media', resultType, searchMessages, lastSyncTime, chatMessages, foundIds,
|
'media', resultType, searchMessages, lastSyncTime, chatMessages, foundIds,
|
||||||
);
|
);
|
||||||
@ -52,8 +57,9 @@ export default function useProfileViewportIds(
|
|||||||
|
|
||||||
switch (resultType) {
|
switch (resultType) {
|
||||||
case 'members':
|
case 'members':
|
||||||
viewportIds = memberIds;
|
viewportIds = memberViewportIds;
|
||||||
getMore = undefined;
|
getMore = getMoreMembers;
|
||||||
|
noProfileInfo = noProfileInfoForMembers;
|
||||||
break;
|
break;
|
||||||
case 'media':
|
case 'media':
|
||||||
viewportIds = mediaViewportIds;
|
viewportIds = mediaViewportIds;
|
||||||
@ -80,6 +86,24 @@ export default function useProfileViewportIds(
|
|||||||
return [resultType, viewportIds, getMore, noProfileInfo] as const;
|
return [resultType, viewportIds, getMore, noProfileInfo] as const;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function useInfiniteScrollForMembers(
|
||||||
|
currentResultType?: ProfileTabType,
|
||||||
|
handleLoadMore?: AnyToVoidFunction,
|
||||||
|
lastSyncTime?: number,
|
||||||
|
memberIds?: number[],
|
||||||
|
) {
|
||||||
|
const [viewportIds, getMore] = useInfiniteScroll(
|
||||||
|
lastSyncTime ? handleLoadMore : undefined,
|
||||||
|
memberIds,
|
||||||
|
undefined,
|
||||||
|
MEMBERS_SLICE,
|
||||||
|
);
|
||||||
|
|
||||||
|
const isOnTop = !viewportIds || !memberIds || viewportIds[0] === memberIds[0];
|
||||||
|
|
||||||
|
return [viewportIds, getMore, !isOnTop] as const;
|
||||||
|
}
|
||||||
|
|
||||||
function useInfiniteScrollForSharedMedia(
|
function useInfiniteScrollForSharedMedia(
|
||||||
forSharedMediaType: SharedMediaType,
|
forSharedMediaType: SharedMediaType,
|
||||||
currentResultType?: ProfileTabType,
|
currentResultType?: ProfileTabType,
|
||||||
|
|||||||
@ -36,7 +36,7 @@ const InfiniteScroll: FC<OwnProps> = ({
|
|||||||
itemSelector = DEFAULT_LIST_SELECTOR,
|
itemSelector = DEFAULT_LIST_SELECTOR,
|
||||||
preloadBackwards = DEFAULT_PRELOAD_BACKWARDS,
|
preloadBackwards = DEFAULT_PRELOAD_BACKWARDS,
|
||||||
sensitiveArea = DEFAULT_SENSITIVE_AREA,
|
sensitiveArea = DEFAULT_SENSITIVE_AREA,
|
||||||
// Used to turn off restoring scroll position (e.g. for frequently re-ordered chat or user lists)
|
// Used to turn off preloading and restoring scroll position (e.g. for frequently re-ordered chat or user lists)
|
||||||
isDisabled = false,
|
isDisabled = false,
|
||||||
noFastList,
|
noFastList,
|
||||||
// Used to re-query `listItemElements` if rendering is delayed by transition
|
// Used to re-query `listItemElements` if rendering is delayed by transition
|
||||||
@ -70,7 +70,7 @@ const InfiniteScroll: FC<OwnProps> = ({
|
|||||||
|
|
||||||
// Initial preload
|
// Initial preload
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!loadMoreBackwards) {
|
if (isDisabled || !loadMoreBackwards) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ const InfiniteScroll: FC<OwnProps> = ({
|
|||||||
loadMoreBackwards();
|
loadMoreBackwards();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [items, loadMoreBackwards, preloadBackwards]);
|
}, [isDisabled, items, loadMoreBackwards, preloadBackwards]);
|
||||||
|
|
||||||
// Restore `scrollTop` after adding items
|
// Restore `scrollTop` after adding items
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
|
|||||||
@ -53,13 +53,14 @@ export const CHAT_LIST_LOAD_SLICE = 100;
|
|||||||
export const SHARED_MEDIA_SLICE = 42;
|
export const SHARED_MEDIA_SLICE = 42;
|
||||||
export const MESSAGE_SEARCH_SLICE = 42;
|
export const MESSAGE_SEARCH_SLICE = 42;
|
||||||
export const GLOBAL_SEARCH_SLICE = 20;
|
export const GLOBAL_SEARCH_SLICE = 20;
|
||||||
export const CHANNEL_MEMBERS_LIMIT = 30;
|
export const MEMBERS_SLICE = 30;
|
||||||
|
export const MEMBERS_LOAD_SLICE = 200;
|
||||||
export const PINNED_MESSAGES_LIMIT = 50;
|
export const PINNED_MESSAGES_LIMIT = 50;
|
||||||
export const BLOCKED_LIST_LIMIT = 100;
|
export const BLOCKED_LIST_LIMIT = 100;
|
||||||
export const PROFILE_PHOTOS_LIMIT = 40;
|
export const PROFILE_PHOTOS_LIMIT = 40;
|
||||||
|
|
||||||
export const TOP_CHAT_MESSAGES_PRELOAD_LIMIT = 25;
|
export const TOP_CHAT_MESSAGES_PRELOAD_LIMIT = 0;
|
||||||
export const ALL_CHATS_PRELOAD_DISABLED = false;
|
export const ALL_CHATS_PRELOAD_DISABLED = true;
|
||||||
|
|
||||||
export const ANIMATION_LEVEL_MIN = 0;
|
export const ANIMATION_LEVEL_MIN = 0;
|
||||||
export const ANIMATION_LEVEL_MED = 1;
|
export const ANIMATION_LEVEL_MED = 1;
|
||||||
|
|||||||
@ -397,7 +397,7 @@ export type ActionTypes = (
|
|||||||
'joinChannel' | 'leaveChannel' | 'deleteChannel' | 'toggleChatPinned' | 'toggleChatArchived' | 'toggleChatUnread' |
|
'joinChannel' | 'leaveChannel' | 'deleteChannel' | 'toggleChatPinned' | 'toggleChatArchived' | 'toggleChatUnread' |
|
||||||
'loadChatFolders' | 'loadRecommendedChatFolders' | 'editChatFolder' | 'addChatFolder' | 'deleteChatFolder' |
|
'loadChatFolders' | 'loadRecommendedChatFolders' | 'editChatFolder' | 'addChatFolder' | 'deleteChatFolder' |
|
||||||
'updateChat' | 'toggleSignatures' | 'loadGroupsForDiscussion' | 'linkDiscussionGroup' | 'unlinkDiscussionGroup' |
|
'updateChat' | 'toggleSignatures' | 'loadGroupsForDiscussion' | 'linkDiscussionGroup' | 'unlinkDiscussionGroup' |
|
||||||
'loadProfilePhotos' |
|
'loadProfilePhotos' | 'loadMoreMembers' |
|
||||||
// messages
|
// messages
|
||||||
'loadViewportMessages' | 'selectMessage' | 'sendMessage' | 'cancelSendingMessage' | 'pinMessage' | 'deleteMessages' |
|
'loadViewportMessages' | 'selectMessage' | 'sendMessage' | 'cancelSendingMessage' | 'pinMessage' | 'deleteMessages' |
|
||||||
'markMessageListRead' | 'markMessagesRead' | 'loadMessage' | 'focusMessage' | 'focusLastMessage' | 'sendPollVote' |
|
'markMessageListRead' | 'markMessagesRead' | 'loadMessage' | 'focusMessage' | 'focusLastMessage' | 'sendPollVote' |
|
||||||
|
|||||||
@ -52,7 +52,7 @@ const TMP_CHAT_ID = -1;
|
|||||||
|
|
||||||
const runThrottledForLoadChats = throttle((cb) => cb(), 1000, true);
|
const runThrottledForLoadChats = throttle((cb) => cb(), 1000, true);
|
||||||
const runThrottledForLoadTopChats = throttle((cb) => cb(), 3000, true);
|
const runThrottledForLoadTopChats = throttle((cb) => cb(), 3000, true);
|
||||||
const runDebouncedForFetchFullChat = debounce((cb) => cb(), 500, false, true);
|
const runDebouncedForLoadFullChat = debounce((cb) => cb(), 500, false, true);
|
||||||
|
|
||||||
addReducer('preloadTopChatMessages', (global, actions) => {
|
addReducer('preloadTopChatMessages', (global, actions) => {
|
||||||
(async () => {
|
(async () => {
|
||||||
@ -173,7 +173,7 @@ addReducer('loadFullChat', (global, actions, payload) => {
|
|||||||
if (force) {
|
if (force) {
|
||||||
loadFullChat(chat);
|
loadFullChat(chat);
|
||||||
} else {
|
} else {
|
||||||
runDebouncedForFetchFullChat(() => loadFullChat(chat));
|
runDebouncedForLoadFullChat(() => loadFullChat(chat));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -669,6 +669,40 @@ addReducer('unlinkDiscussionGroup', (global, actions, payload) => {
|
|||||||
})();
|
})();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addReducer('loadMoreMembers', (global) => {
|
||||||
|
(async () => {
|
||||||
|
const { chatId } = selectCurrentMessageList(global) || {};
|
||||||
|
const chat = chatId ? selectChat(global, chatId) : undefined;
|
||||||
|
if (!chat) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const offset = (chat.fullInfo && chat.fullInfo.members && chat.fullInfo.members.length) || undefined;
|
||||||
|
const result = await callApi('fetchMembers', chat.id, chat.accessHash!, 'recent', offset);
|
||||||
|
if (!result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { members, users } = result;
|
||||||
|
if (!members || !members.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
global = getGlobal();
|
||||||
|
global = addUsers(global, buildCollectionByKey(users, 'id'));
|
||||||
|
global = updateChat(global, chat.id, {
|
||||||
|
fullInfo: {
|
||||||
|
...chat.fullInfo,
|
||||||
|
members: [
|
||||||
|
...((chat.fullInfo || {}).members || []),
|
||||||
|
...(members || []),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
setGlobal(global);
|
||||||
|
})();
|
||||||
|
});
|
||||||
|
|
||||||
async function loadChats(listType: 'active' | 'archived', offsetId?: number, offsetDate?: number) {
|
async function loadChats(listType: 'active' | 'archived', offsetId?: number, offsetDate?: number) {
|
||||||
const result = await callApi('fetchChats', {
|
const result = await callApi('fetchChats', {
|
||||||
limit: CHAT_LIST_LOAD_SLICE,
|
limit: CHAT_LIST_LOAD_SLICE,
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import {
|
|||||||
getPrivateChatUserId, isChatChannel, isChatPrivate, isHistoryClearMessage, isUserBot, isUserOnline,
|
getPrivateChatUserId, isChatChannel, isChatPrivate, isHistoryClearMessage, isUserBot, isUserOnline,
|
||||||
} from '../helpers';
|
} from '../helpers';
|
||||||
import { selectUser } from './users';
|
import { selectUser } from './users';
|
||||||
import { ALL_FOLDER_ID, ARCHIVED_FOLDER_ID, CHANNEL_MEMBERS_LIMIT } from '../../config';
|
import { ALL_FOLDER_ID, ARCHIVED_FOLDER_ID, MEMBERS_LOAD_SLICE } from '../../config';
|
||||||
|
|
||||||
export function selectChat(global: GlobalState, chatId: number): ApiChat | undefined {
|
export function selectChat(global: GlobalState, chatId: number): ApiChat | undefined {
|
||||||
return global.chats.byId[chatId];
|
return global.chats.byId[chatId];
|
||||||
@ -38,7 +38,7 @@ export function selectChatOnlineCount(global: GlobalState, chat: ApiChat) {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!chat.fullInfo.members || chat.fullInfo.members.length === CHANNEL_MEMBERS_LIMIT) {
|
if (!chat.fullInfo.members || chat.fullInfo.members.length === MEMBERS_LOAD_SLICE) {
|
||||||
return chat.fullInfo.onlineCount;
|
return chat.fullInfo.onlineCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user