Convert SearchHeader to reusable component and minor tweaks to DiscussionMessagesView

This commit is contained in:
Gerzon Z 2021-09-08 19:56:35 -04:00
parent ad612e6073
commit 91dedfb620
6 changed files with 92 additions and 80 deletions

View File

@ -0,0 +1,52 @@
import React from 'react';
import { StyleSheet, View } from 'react-native';
import PropTypes from 'prop-types';
import { withDimensions } from '../dimensions';
import { isIOS, isTablet } from '../utils/deviceInfo';
import { themes } from '../constants/colors';
import sharedStyles from '../views/Styles';
import TextInput from '../presentation/TextInput';
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
marginLeft: 0
},
title: {
...sharedStyles.textSemibold
}
});
const SearchHeader = ({
onSearchChangeText, placeholder, theme, testID, width, height
}) => {
const isLight = theme === 'light';
const isLandscape = width > height;
const scale = isIOS && isLandscape && !isTablet ? 0.8 : 1;
const titleFontSize = 16 * scale;
return (
<View style={styles.container}>
<TextInput
autoFocus
style={[styles.title, isLight && { color: themes[theme].headerTitleColor }, { fontSize: titleFontSize }]}
placeholder={placeholder}
onChangeText={onSearchChangeText}
theme={theme}
testID={testID}
/>
</View>
);
};
SearchHeader.propTypes = {
onSearchChangeText: PropTypes.func.isRequired,
placeholder: PropTypes.string.isRequired,
theme: PropTypes.string,
testID: PropTypes.string,
width: PropTypes.number,
height: PropTypes.number
};
export default withDimensions(SearchHeader);

View File

@ -799,7 +799,7 @@ const RocketChat = {
}); });
}, },
getDiscussions({ getDiscussions({
roomId, offset, count, text = '' roomId, offset, count, text
}) { }) {
const params = { const params = {
roomId, roomId,

View File

@ -1,4 +1,3 @@
/* eslint-disable react/prop-types */
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { FlatList } from 'react-native'; import { FlatList } from 'react-native';
@ -18,10 +17,11 @@ import * as List from '../containers/List';
import BackgroundContainer from '../containers/BackgroundContainer'; import BackgroundContainer from '../containers/BackgroundContainer';
import { isIOS } from '../utils/deviceInfo'; import { isIOS } from '../utils/deviceInfo';
import { getHeaderTitlePosition } from '../containers/Header'; import { getHeaderTitlePosition } from '../containers/Header';
import SearchHeader from './ThreadMessagesView/SearchHeader';
import { useTheme } from '../theme'; import { useTheme } from '../theme';
import Message from '../containers/message'; import Message from '../containers/message';
import RocketChat from '../lib/rocketchat'; import RocketChat from '../lib/rocketchat';
import SearchHeader from '../containers/SearchHeader';
const API_FETCH_COUNT = 25; const API_FETCH_COUNT = 25;
@ -31,19 +31,22 @@ const DiscussionMessagesView = ({ navigation, route }) => {
const autoTranslate = route.params?.autoTranslate; const autoTranslate = route.params?.autoTranslate;
const autoTranslateLanguage = route.params?.autoTranslateLanguage; const autoTranslateLanguage = route.params?.autoTranslateLanguage;
const navToRoomInfo = route.params?.navToRoomInfo; const navToRoomInfo = route.params?.navToRoomInfo;
const user = useSelector(state => state.login?.user); const user = useSelector(state => state.login?.user);
const baseUrl = useSelector(state => state.server.server); const baseUrl = useSelector(state => state.server.server);
const useRealName = useSelector(state => state.settings.UI_Use_Real_Name); const useRealName = useSelector(state => state.settings.UI_Use_Real_Name);
const Message_TimeFormat = useSelector(state => state.settings.Message_TimeFormat); const Message_TimeFormat = useSelector(state => state.settings.Message_TimeFormat);
const isMasterDetail = useSelector(state => state.app.isMasterDetail); const isMasterDetail = useSelector(state => state.app.isMasterDetail);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [discussions, setDiscussions] = useState([]); const [discussions, setDiscussions] = useState([]);
const [search, setSearch] = useState([]); const [search, setSearch] = useState([]);
const [isSearching, setIsSearching] = useState(false); const [isSearching, setIsSearching] = useState(false);
const { theme } = useTheme(); const { theme } = useTheme();
const insets = useSafeAreaInsets(); const insets = useSafeAreaInsets();
const load = async() => { const load = async(text = '') => {
if (loading) { if (loading) {
return; return;
} }
@ -52,8 +55,9 @@ const DiscussionMessagesView = ({ navigation, route }) => {
try { try {
const result = await RocketChat.getDiscussions({ const result = await RocketChat.getDiscussions({
roomId: rid, roomId: rid,
offset: discussions.length, offset: isSearching ? search.length : discussions.length,
count: API_FETCH_COUNT count: API_FETCH_COUNT,
text
}); });
if (result.success) { if (result.success) {
@ -71,22 +75,8 @@ const DiscussionMessagesView = ({ navigation, route }) => {
}; };
const onSearchChangeText = debounce(async(text) => { const onSearchChangeText = debounce(async(text) => {
setLoading(true); setIsSearching(true);
try { await load(text);
const result = await RocketChat.getDiscussions({
roomId: rid,
offset: search.length,
count: API_FETCH_COUNT,
text
});
if (result.success) {
setSearch(result.messages);
}
setLoading(false);
} catch (e) {
log(e);
setLoading(false);
}
}, 300); }, 300);
const onCancelSearchPress = () => { const onCancelSearchPress = () => {
@ -111,7 +101,14 @@ const DiscussionMessagesView = ({ navigation, route }) => {
/> />
</HeaderButton.Container> </HeaderButton.Container>
), ),
headerTitle: () => <SearchHeader placeholder='Search Messages' onSearchChangeText={onSearchChangeText} />, headerTitle: () => (
<SearchHeader
placeholder='Search Messages'
onSearchChangeText={onSearchChangeText}
theme={theme}
testID='discussion-messages-view-search-header'
/>
),
headerTitleContainerStyle: { headerTitleContainerStyle: {
left: headerTitlePosition.left, left: headerTitlePosition.left,
right: headerTitlePosition.right right: headerTitlePosition.right
@ -199,7 +196,7 @@ const DiscussionMessagesView = ({ navigation, route }) => {
windowSize={10} windowSize={10}
initialNumToRender={7} initialNumToRender={7}
removeClippedSubviews={isIOS} removeClippedSubviews={isIOS}
onEndReached={() => discussions.length > 25 ?? load()} onEndReached={() => discussions.length > API_FETCH_COUNT ?? load()}
ItemSeparatorComponent={List.Separator} ItemSeparatorComponent={List.Separator}
ListFooterComponent={loading ? <ActivityIndicator theme={theme} /> : null} ListFooterComponent={loading ? <ActivityIndicator theme={theme} /> : null}
scrollIndicatorInsets={{ right: 1 }} scrollIndicatorInsets={{ right: 1 }}
@ -210,7 +207,10 @@ const DiscussionMessagesView = ({ navigation, route }) => {
DiscussionMessagesView.propTypes = { DiscussionMessagesView.propTypes = {
navigation: PropTypes.object, navigation: PropTypes.object,
route: PropTypes.object route: PropTypes.object,
item: PropTypes.shape({
msg: PropTypes.string
})
}; };
export default DiscussionMessagesView; export default DiscussionMessagesView;

View File

@ -8,7 +8,7 @@ import { connect } from 'react-redux';
import StatusBar from '../containers/StatusBar'; import StatusBar from '../containers/StatusBar';
import RoomHeader from '../containers/RoomHeader'; import RoomHeader from '../containers/RoomHeader';
import { withTheme } from '../theme'; import { withTheme } from '../theme';
import SearchHeader from './ThreadMessagesView/SearchHeader';
import log, { events, logEvent } from '../utils/log'; import log, { events, logEvent } from '../utils/log';
import database from '../lib/database'; import database from '../lib/database';
import { getUserSelector } from '../selectors/login'; import { getUserSelector } from '../selectors/login';
@ -29,6 +29,7 @@ import { withActionSheet } from '../containers/ActionSheet';
import { deleteRoom as deleteRoomAction } from '../actions/room'; import { deleteRoom as deleteRoomAction } from '../actions/room';
import { CustomIcon } from '../lib/Icons'; import { CustomIcon } from '../lib/Icons';
import { themes } from '../constants/colors'; import { themes } from '../constants/colors';
import SearchHeader from '../containers/SearchHeader';
const API_FETCH_COUNT = 25; const API_FETCH_COUNT = 25;
const PERMISSION_DELETE_C = 'delete-c'; const PERMISSION_DELETE_C = 'delete-c';
@ -162,7 +163,9 @@ class TeamChannelsView extends React.Component {
setHeader = () => { setHeader = () => {
const { isSearching, showCreate, data } = this.state; const { isSearching, showCreate, data } = this.state;
const { navigation, isMasterDetail, insets } = this.props; const {
navigation, isMasterDetail, insets, theme
} = this.props;
const { team } = this; const { team } = this;
if (!team) { if (!team) {
@ -182,7 +185,14 @@ class TeamChannelsView extends React.Component {
/> />
</HeaderButton.Container> </HeaderButton.Container>
), ),
headerTitle: () => <SearchHeader onSearchChangeText={this.onSearchChangeText} />, headerTitle: () => (
<SearchHeader
onSearchChangeText={this.onSearchChangeText}
placeholder='Search Channels'
theme={theme}
testID='team-channels-view-search-header'
/>
),
headerTitleContainerStyle: { headerTitleContainerStyle: {
left: headerTitlePosition.left, left: headerTitlePosition.left,
right: headerTitlePosition.right right: headerTitlePosition.right

View File

@ -1,50 +0,0 @@
import React from 'react';
import { StyleSheet, View } from 'react-native';
import PropTypes from 'prop-types';
import { useTheme, withTheme } from '../../theme';
import sharedStyles from '../Styles';
import { themes } from '../../constants/colors';
import TextInput from '../../presentation/TextInput';
import { isTablet, isIOS } from '../../utils/deviceInfo';
import { useOrientation } from '../../dimensions';
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
marginLeft: 0
},
title: {
...sharedStyles.textSemibold
}
});
// TODO: it might be useful to refactor this component for reusage
const SearchHeader = ({ onSearchChangeText, placeholder }) => {
const { theme } = useTheme();
const titleColorStyle = { color: themes[theme].headerTitleColor };
const isLight = theme === 'light';
const { isLandscape } = useOrientation();
const scale = isIOS && isLandscape && !isTablet ? 0.8 : 1;
const titleFontSize = 16 * scale;
return (
<View style={styles.container}>
<TextInput
autoFocus
style={[styles.title, isLight && titleColorStyle, { fontSize: titleFontSize }]}
placeholder={placeholder || 'Search'}
onChangeText={onSearchChangeText}
theme={theme}
testID='thread-messages-view-search-header'
/>
</View>
);
};
SearchHeader.propTypes = {
onSearchChangeText: PropTypes.func,
placeholder: PropTypes.string
};
export default withTheme(SearchHeader);

View File

@ -32,9 +32,9 @@ import BackgroundContainer from '../../containers/BackgroundContainer';
import { isIOS } from '../../utils/deviceInfo'; import { isIOS } from '../../utils/deviceInfo';
import { getBadgeColor, makeThreadName } from '../../utils/room'; import { getBadgeColor, makeThreadName } from '../../utils/room';
import { getHeaderTitlePosition } from '../../containers/Header'; import { getHeaderTitlePosition } from '../../containers/Header';
import SearchHeader from './SearchHeader';
import EventEmitter from '../../utils/events'; import EventEmitter from '../../utils/events';
import { LISTENER } from '../../containers/Toast'; import { LISTENER } from '../../containers/Toast';
import SearchHeader from '../../containers/SearchHeader';
const API_FETCH_COUNT = 50; const API_FETCH_COUNT = 50;
@ -113,7 +113,7 @@ class ThreadMessagesView extends React.Component {
/> />
</HeaderButton.Container> </HeaderButton.Container>
), ),
headerTitle: () => <SearchHeader onSearchChangeText={this.onSearchChangeText} />, headerTitle: () => <SearchHeader onSearchChangeText={this.onSearchChangeText} placeholder='Search' theme={theme} testID='thread-messages-view-search-header' />,
headerTitleContainerStyle: { headerTitleContainerStyle: {
left: headerTitlePosition.left, left: headerTitlePosition.left,
right: headerTitlePosition.right right: headerTitlePosition.right