Message List: Scroll notch (#1129)

This commit is contained in:
Alexander Zinchuk 2021-05-31 15:08:51 +03:00
parent b71e589620
commit 839b6b65f2
6 changed files with 53 additions and 5 deletions

View File

@ -5,7 +5,7 @@
overflow: scroll; overflow: scroll;
overflow-x: hidden; overflow-x: hidden;
overflow-y: overlay; overflow-y: overlay;
margin-bottom: .3125rem; margin-bottom: .5rem;
.mask-image-enabled & { .mask-image-enabled & {
mask-image: linear-gradient(to top, transparent 0, #000 0.5rem); mask-image: linear-gradient(to top, transparent 0, #000 0.5rem);

View File

@ -66,7 +66,8 @@ type OwnProps = {
threadId: number; threadId: number;
type: MessageListType; type: MessageListType;
canPost: boolean; canPost: boolean;
onFabToggle: (show: boolean) => void; onFabToggle: (shouldShow: boolean) => void;
onNotchToggle: (shouldShow: boolean) => void;
hasTools?: boolean; hasTools?: boolean;
}; };
@ -114,6 +115,7 @@ const MessageList: FC<OwnProps & StateProps & DispatchProps> = ({
type, type,
hasTools, hasTools,
onFabToggle, onFabToggle,
onNotchToggle,
isChatLoaded, isChatLoaded,
isChannelChat, isChannelChat,
canPost, canPost,
@ -540,6 +542,7 @@ const MessageList: FC<OwnProps & StateProps & DispatchProps> = ({
isViewportNewest={isViewportNewest} isViewportNewest={isViewportNewest}
firstUnreadId={firstUnreadId} firstUnreadId={firstUnreadId}
onFabToggle={onFabToggle} onFabToggle={onFabToggle}
onNotchToggle={onNotchToggle}
> >
{renderMessages( {renderMessages(
lang, lang,

View File

@ -19,6 +19,7 @@ type OwnProps = {
isViewportNewest?: boolean; isViewportNewest?: boolean;
firstUnreadId?: number; firstUnreadId?: number;
onFabToggle: AnyToVoidFunction; onFabToggle: AnyToVoidFunction;
onNotchToggle: AnyToVoidFunction;
children: any; children: any;
}; };
@ -38,6 +39,7 @@ const MessageScroll: FC<OwnProps> = ({
isViewportNewest, isViewportNewest,
firstUnreadId, firstUnreadId,
onFabToggle, onFabToggle,
onNotchToggle,
children, children,
}) => { }) => {
// eslint-disable-next-line no-null/no-null // eslint-disable-next-line no-null/no-null
@ -54,11 +56,13 @@ const MessageScroll: FC<OwnProps> = ({
if (!messageIds || !messageIds.length) { if (!messageIds || !messageIds.length) {
onFabToggle(false); onFabToggle(false);
onNotchToggle(false);
return; return;
} }
if (!isViewportNewest) { if (!isViewportNewest) {
onFabToggle(true); onFabToggle(true);
onNotchToggle(true);
return; return;
} }
@ -68,7 +72,8 @@ const MessageScroll: FC<OwnProps> = ({
const isAtBottom = scrollBottom === 0 || (IS_SAFARI && scrollBottom === 1); const isAtBottom = scrollBottom === 0 || (IS_SAFARI && scrollBottom === 1);
onFabToggle(firstUnreadId ? !isAtBottom : !isNearBottom); onFabToggle(firstUnreadId ? !isAtBottom : !isNearBottom);
}, [messageIds, isViewportNewest, containerRef, onFabToggle, firstUnreadId]); onNotchToggle(!isAtBottom);
}, [messageIds, isViewportNewest, containerRef, onFabToggle, firstUnreadId, onNotchToggle]);
const { const {
observe: observeIntersection, observe: observeIntersection,
@ -114,6 +119,16 @@ const MessageScroll: FC<OwnProps> = ({
useOnIntersect(fabTriggerRef, observeIntersectionForFab); useOnIntersect(fabTriggerRef, observeIntersectionForFab);
const {
observe: observeIntersectionForNotch,
} = useIntersectionObserver({
rootRef: containerRef,
}, () => {
updateFabVisibility();
});
useOnIntersect(fabTriggerRef, observeIntersectionForNotch);
// Do not load more and show FAB when focusing // Do not load more and show FAB when focusing
useOnChange(() => { useOnChange(() => {
if (focusingId) { if (focusingId) {

View File

@ -255,6 +255,27 @@
transform: translate3d(0, calc(-1 * (var(--symbol-menu-height) + var(--symbol-menu-footer-height))), 0); transform: translate3d(0, calc(-1 * (var(--symbol-menu-height) + var(--symbol-menu-footer-height))), 0);
} }
} }
&::before {
content: "";
position: absolute;
top: -0.5rem;
left: 0;
right: 0;
height: 1px;
background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.4) 2%, rgba(255, 255, 255, 0.4) 98%, rgba(255, 255, 255, 0) 100%);
opacity: 0;
transition: opacity 200ms ease;
@media (max-width: 600px) {
left: -2%;
right: -2%;
}
}
&.with-notch::before {
opacity: 1;
}
} }
} }

View File

@ -103,6 +103,7 @@ const MiddleColumn: FC<StateProps & DispatchProps> = ({
const [dropAreaState, setDropAreaState] = useState(DropAreaState.None); const [dropAreaState, setDropAreaState] = useState(DropAreaState.None);
const [isFabShown, setIsFabShown] = useState<boolean | undefined>(); const [isFabShown, setIsFabShown] = useState<boolean | undefined>();
const [isNotchShown, setIsNotchShown] = useState<boolean | undefined>();
const [isUnpinModalOpen, setIsUnpinModalOpen] = useState(false); const [isUnpinModalOpen, setIsUnpinModalOpen] = useState(false);
const hasTools = hasPinnedOrAudioMessage && ( const hasTools = hasPinnedOrAudioMessage && (
@ -134,6 +135,7 @@ const MiddleColumn: FC<StateProps & DispatchProps> = ({
useEffect(() => { useEffect(() => {
setDropAreaState(DropAreaState.None); setDropAreaState(DropAreaState.None);
setIsFabShown(undefined); setIsFabShown(undefined);
setIsNotchShown(undefined);
}, [chatId]); }, [chatId]);
useEffect(() => { useEffect(() => {
@ -198,6 +200,12 @@ const MiddleColumn: FC<StateProps & DispatchProps> = ({
const lang = useLang(); const lang = useLang();
const footerClassName = buildClassName(
'middle-column-footer',
!renderingCanPost && 'no-composer',
renderingCanPost && isNotchShown && 'with-notch',
);
return ( return (
<div <div
id="MiddleColumn" id="MiddleColumn"
@ -242,8 +250,9 @@ const MiddleColumn: FC<StateProps & DispatchProps> = ({
canPost={renderingCanPost} canPost={renderingCanPost}
hasTools={renderingHasTools} hasTools={renderingHasTools}
onFabToggle={setIsFabShown} onFabToggle={setIsFabShown}
onNotchToggle={setIsNotchShown}
/> />
<div className={buildClassName('middle-column-footer', !renderingCanPost && 'no-composer')}> <div className={footerClassName}>
{renderingCanPost && ( {renderingCanPost && (
<Composer <Composer
chatId={renderingChatId} chatId={renderingChatId}

View File

@ -46,7 +46,7 @@
} }
&.last-in-list { &.last-in-list {
margin-bottom: 0.375rem; margin-bottom: 0rem;
} }
&.is-in-selection-mode { &.is-in-selection-mode {