diff --git a/app/components/post_list/post_list.ios.js b/app/components/post_list/post_list.ios.js index 4be27931f..e4ac1a203 100644 --- a/app/components/post_list/post_list.ios.js +++ b/app/components/post_list/post_list.ios.js @@ -4,7 +4,10 @@ import React from 'react'; import {FlatList, StyleSheet} from 'react-native'; +import {debounce} from 'mattermost-redux/actions/helpers'; + import {ListTypes} from 'app/constants'; +import {THREAD} from 'app/constants/screen'; import {makeExtraData} from 'app/utils/list_view'; import PostListBase from './post_list_base'; @@ -59,8 +62,8 @@ export default class PostList extends PostListBase { handleScroll = (event) => { const pageOffsetY = event.nativeEvent.contentOffset.y; + const contentHeight = event.nativeEvent.contentSize.height; if (pageOffsetY > 0) { - const contentHeight = event.nativeEvent.contentSize.height; const direction = (this.contentOffsetY < pageOffsetY) ? ListTypes.VISIBILITY_SCROLL_UP : ListTypes.VISIBILITY_SCROLL_DOWN; @@ -72,9 +75,26 @@ export default class PostList extends PostListBase { ) { this.props.onLoadMoreUp(); } + } else if (pageOffsetY < 0) { + if (this.state.postListHeight > contentHeight || this.props.location === THREAD) { + // Posting a message like multiline or jumbo emojis causes the FlatList component for iOS + // to render RefreshControl component and remain the space as is when it's unmounted, + // leaving a whitespace of ~64 units of height between input box and post list. + // This condition explicitly pull down the list to recent post when pageOffsetY is less than zero, + // and the height of the layout is greater than its content or is on a thread screen. + this.handleScrollToRecentPost(); + } } }; + handleScrollToRecentPost = debounce(() => { + this.refs.list.scrollToIndex({ + animated: true, + index: 0, + viewPosition: 1, + }); + }, 100); + handleScrollToIndexFailed = () => { requestAnimationFrame(() => { this.hasDoneInitialScroll = false; diff --git a/app/components/post_list/post_list_base.js b/app/components/post_list/post_list_base.js index 3a26237e5..9a48f8750 100644 --- a/app/components/post_list/post_list_base.js +++ b/app/components/post_list/post_list_base.js @@ -44,6 +44,7 @@ export default class PostListBase extends PureComponent { shouldRenderReplyButton: PropTypes.bool, siteURL: PropTypes.string.isRequired, theme: PropTypes.object.isRequired, + location: PropTypes.string, }; static defaultProps = { diff --git a/app/constants/screen.js b/app/constants/screen.js new file mode 100644 index 000000000..8c8a0ec9d --- /dev/null +++ b/app/constants/screen.js @@ -0,0 +1,4 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +export const THREAD = 'thread'; diff --git a/app/screens/thread/__snapshots__/thread.test.js.snap b/app/screens/thread/__snapshots__/thread.test.js.snap index 32821f032..f5827dc9e 100644 --- a/app/screens/thread/__snapshots__/thread.test.js.snap +++ b/app/screens/thread/__snapshots__/thread.test.js.snap @@ -17,6 +17,7 @@ exports[`thread should match snapshot, has root post 1`] = ` );