Forward Picker: Smooth scroll on mobile
This commit is contained in:
parent
9c04a2eaa5
commit
e7026aa16c
@ -46,7 +46,7 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding: 0 1rem 1rem;
|
padding: 0 0.5rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,6 +60,15 @@
|
|||||||
color: var(--color-text-secondary);
|
color: var(--color-text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.scroll-container {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ListItem {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.ListItem.chat-item-clickable {
|
.ListItem.chat-item-clickable {
|
||||||
&:not(.force-rounded-corners) {
|
&:not(.force-rounded-corners) {
|
||||||
@media (max-width: 600px) {
|
@media (max-width: 600px) {
|
||||||
|
|||||||
@ -3,6 +3,8 @@ import React, {
|
|||||||
FC, memo, useRef, useCallback,
|
FC, memo, useRef, useCallback,
|
||||||
} from '../../lib/teact/teact';
|
} from '../../lib/teact/teact';
|
||||||
|
|
||||||
|
import { CHAT_HEIGHT_PX } from '../../config';
|
||||||
|
import { IS_ANDROID } from '../../util/environment';
|
||||||
import useInfiniteScroll from '../../hooks/useInfiniteScroll';
|
import useInfiniteScroll from '../../hooks/useInfiniteScroll';
|
||||||
import useLang from '../../hooks/useLang';
|
import useLang from '../../hooks/useLang';
|
||||||
import useKeyboardListNavigation from '../../hooks/useKeyboardListNavigation';
|
import useKeyboardListNavigation from '../../hooks/useKeyboardListNavigation';
|
||||||
@ -27,10 +29,11 @@ export type OwnProps = {
|
|||||||
filterRef: RefObject<HTMLInputElement>;
|
filterRef: RefObject<HTMLInputElement>;
|
||||||
filterPlaceholder: string;
|
filterPlaceholder: string;
|
||||||
filter: string;
|
filter: string;
|
||||||
onFilterChange: (filter: string) => void;
|
|
||||||
loadMore: NoneToVoidFunction;
|
loadMore: NoneToVoidFunction;
|
||||||
|
onFilterChange: (filter: string) => void;
|
||||||
onSelectChatOrUser: (chatOrUserId: string) => void;
|
onSelectChatOrUser: (chatOrUserId: string) => void;
|
||||||
onClose: NoneToVoidFunction;
|
onClose: NoneToVoidFunction;
|
||||||
|
onCloseAnimationEnd?: NoneToVoidFunction;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ChatOrUserPicker: FC<OwnProps> = ({
|
const ChatOrUserPicker: FC<OwnProps> = ({
|
||||||
@ -40,10 +43,11 @@ const ChatOrUserPicker: FC<OwnProps> = ({
|
|||||||
filterRef,
|
filterRef,
|
||||||
filter,
|
filter,
|
||||||
filterPlaceholder,
|
filterPlaceholder,
|
||||||
onFilterChange,
|
|
||||||
onClose,
|
|
||||||
loadMore,
|
loadMore,
|
||||||
|
onFilterChange,
|
||||||
onSelectChatOrUser,
|
onSelectChatOrUser,
|
||||||
|
onClose,
|
||||||
|
onCloseAnimationEnd,
|
||||||
}) => {
|
}) => {
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
const [viewportIds, getMore] = useInfiniteScroll(loadMore, chatOrUserIds, Boolean(filter));
|
const [viewportIds, getMore] = useInfiniteScroll(loadMore, chatOrUserIds, Boolean(filter));
|
||||||
@ -85,35 +89,47 @@ const ChatOrUserPicker: FC<OwnProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const viewportOffset = chatOrUserIds!.indexOf(viewportIds![0]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
onClose={onClose}
|
|
||||||
className="ChatOrUserPicker"
|
className="ChatOrUserPicker"
|
||||||
header={modalHeader}
|
header={modalHeader}
|
||||||
|
onClose={onClose}
|
||||||
|
onCloseAnimationEnd={onCloseAnimationEnd}
|
||||||
>
|
>
|
||||||
{viewportIds?.length ? (
|
{viewportIds?.length ? (
|
||||||
<InfiniteScroll
|
<InfiniteScroll
|
||||||
|
ref={containerRef}
|
||||||
className="picker-list custom-scroll"
|
className="picker-list custom-scroll"
|
||||||
items={viewportIds}
|
items={viewportIds}
|
||||||
onLoadMore={getMore}
|
onLoadMore={getMore}
|
||||||
noScrollRestore={Boolean(filter)}
|
noFastList
|
||||||
ref={containerRef}
|
noScrollRestore
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
>
|
>
|
||||||
{viewportIds.map((id) => (
|
<div
|
||||||
<ListItem
|
className="scroll-container"
|
||||||
key={id}
|
// @ts-ignore
|
||||||
className="chat-item-clickable force-rounded-corners"
|
style={IS_ANDROID ? `height: ${chatOrUserIds!.length * CHAT_HEIGHT_PX}px` : undefined}
|
||||||
onClick={() => onSelectChatOrUser(id)}
|
teactFastList
|
||||||
>
|
>
|
||||||
{isUserId(id) ? (
|
{viewportIds.map((id, i) => (
|
||||||
<PrivateChatInfo status={id === currentUserId ? lang('SavedMessagesInfo') : undefined} userId={id} />
|
<ListItem
|
||||||
) : (
|
key={id}
|
||||||
<GroupChatInfo chatId={id} />
|
className="chat-item-clickable force-rounded-corners"
|
||||||
)}
|
style={`top: ${(viewportOffset + i) * CHAT_HEIGHT_PX}px;`}
|
||||||
</ListItem>
|
onClick={() => onSelectChatOrUser(id)}
|
||||||
))}
|
>
|
||||||
|
{isUserId(id) ? (
|
||||||
|
<PrivateChatInfo status={id === currentUserId ? lang('SavedMessagesInfo') : undefined} userId={id} />
|
||||||
|
) : (
|
||||||
|
<GroupChatInfo chatId={id} />
|
||||||
|
)}
|
||||||
|
</ListItem>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</InfiniteScroll>
|
</InfiniteScroll>
|
||||||
) : viewportIds && !viewportIds.length ? (
|
) : viewportIds && !viewportIds.length ? (
|
||||||
<p className="no-results">{lang('lng_blocked_list_not_found')}</p>
|
<p className="no-results">{lang('lng_blocked_list_not_found')}</p>
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import React, {
|
import React, {
|
||||||
FC, useMemo, useState, memo, useRef, useCallback,
|
FC, useMemo, useState, memo, useRef, useCallback, useEffect,
|
||||||
} from '../../lib/teact/teact';
|
} from '../../lib/teact/teact';
|
||||||
import { getDispatch, getGlobal, withGlobal } from '../../lib/teact/teactn';
|
import { getDispatch, getGlobal, withGlobal } from '../../lib/teact/teactn';
|
||||||
|
|
||||||
@ -14,6 +14,7 @@ import {
|
|||||||
import { unique } from '../../util/iteratees';
|
import { unique } from '../../util/iteratees';
|
||||||
import useLang from '../../hooks/useLang';
|
import useLang from '../../hooks/useLang';
|
||||||
import useCurrentOrPrev from '../../hooks/useCurrentOrPrev';
|
import useCurrentOrPrev from '../../hooks/useCurrentOrPrev';
|
||||||
|
import useFlag from '../../hooks/useFlag';
|
||||||
|
|
||||||
import ChatOrUserPicker from '../common/ChatOrUserPicker';
|
import ChatOrUserPicker from '../common/ChatOrUserPicker';
|
||||||
|
|
||||||
@ -50,6 +51,13 @@ const ForwardPicker: FC<OwnProps & StateProps> = ({
|
|||||||
// eslint-disable-next-line no-null/no-null
|
// eslint-disable-next-line no-null/no-null
|
||||||
const filterRef = useRef<HTMLInputElement>(null);
|
const filterRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
const [isShown, markIsShown, unmarkIsShown] = useFlag();
|
||||||
|
useEffect(() => {
|
||||||
|
if (isOpen) {
|
||||||
|
markIsShown();
|
||||||
|
}
|
||||||
|
}, [isOpen, markIsShown]);
|
||||||
|
|
||||||
const chatAndContactIds = useMemo(() => {
|
const chatAndContactIds = useMemo(() => {
|
||||||
if (!isOpen) {
|
if (!isOpen) {
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -82,7 +90,11 @@ const ForwardPicker: FC<OwnProps & StateProps> = ({
|
|||||||
setForwardChatId({ id: userId });
|
setForwardChatId({ id: userId });
|
||||||
}, [setForwardChatId]);
|
}, [setForwardChatId]);
|
||||||
|
|
||||||
const renderingChatAndContactIds = useCurrentOrPrev(chatAndContactIds)!;
|
const renderingChatAndContactIds = useCurrentOrPrev(chatAndContactIds, true)!;
|
||||||
|
|
||||||
|
if (!isOpen && !isShown) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ChatOrUserPicker
|
<ChatOrUserPicker
|
||||||
@ -96,6 +108,7 @@ const ForwardPicker: FC<OwnProps & StateProps> = ({
|
|||||||
loadMore={loadMoreChats}
|
loadMore={loadMoreChats}
|
||||||
onSelectChatOrUser={handleSelectUser}
|
onSelectChatOrUser={handleSelectUser}
|
||||||
onClose={exitForwardMode}
|
onClose={exitForwardMode}
|
||||||
|
onCloseAnimationEnd={unmarkIsShown}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -147,8 +147,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.chat-item-clickable {
|
&.chat-item-clickable {
|
||||||
margin: 0 -0.5rem;
|
|
||||||
|
|
||||||
body.is-ios &,
|
body.is-ios &,
|
||||||
body.is-macos & {
|
body.is-macos & {
|
||||||
--color-text-secondary: var(--color-text-secondary-apple);
|
--color-text-secondary: var(--color-text-secondary-apple);
|
||||||
|
|||||||
@ -34,6 +34,10 @@ const useInfiniteScroll = <ListId extends string | number>(
|
|||||||
|
|
||||||
const forceUpdate = useForceUpdate();
|
const forceUpdate = useForceUpdate();
|
||||||
|
|
||||||
|
if (isDisabled) {
|
||||||
|
lastParamsRef.current = {};
|
||||||
|
}
|
||||||
|
|
||||||
const prevListIds = usePrevious(listIds);
|
const prevListIds = usePrevious(listIds);
|
||||||
const prevIsDisabled = usePrevious(isDisabled);
|
const prevIsDisabled = usePrevious(isDisabled);
|
||||||
if (listIds && !isDisabled && (listIds !== prevListIds || isDisabled !== prevIsDisabled)) {
|
if (listIds && !isDisabled && (listIds !== prevListIds || isDisabled !== prevIsDisabled)) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user