[NEW] Basic support to Teams (#3016)
* Database migration * RoomItem icon * Team icons * Teams group * Small tweak on RoomTypeIcon * RoomView Header * Add team's channels to RoomView header * Starting TeamChannelsView * Icon size * o data found * Update TeamChannelsView, add teams subscriptions and send params to TeamChannelsView * Use teams.ListRooms endpoint, render rooms list, remove unused functions * Show team main on TeamChannelsView * Disable swipe * Pagination working * Fix blinking no data found * Search working * Refactor to use BackgroundContainer while loading * Go to room * Cleanup * Go to actions * Events * Lint * Add debounce to go room * Fix for tablet * i18n * Small fix * Minor refactor * Use local data when it exists * Show last message * Force teams migration * Add stories to BackgroundContainer * Remove unused component * Move RoomViewHeader into containers folder * Refactoring * Testing RoomHeader * i18n * Fix server endpoint version * Fix events Co-authored-by: Gerzon Z <gerzonzcanario@gmail.com>
This commit is contained in:
parent
5a96f1ff6b
commit
d04d0f27b6
File diff suppressed because it is too large
Load Diff
|
@ -1,11 +1,11 @@
|
|||
import React from 'react';
|
||||
import {
|
||||
ImageBackground, StyleSheet, Text, View
|
||||
ImageBackground, StyleSheet, Text, View, ActivityIndicator
|
||||
} from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { withTheme } from '../../theme';
|
||||
import sharedStyles from '../Styles';
|
||||
import sharedStyles from '../../views/Styles';
|
||||
import { themes } from '../../constants/colors';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
|
@ -29,15 +29,17 @@ const styles = StyleSheet.create({
|
|||
}
|
||||
});
|
||||
|
||||
const EmptyRoom = ({ theme, text }) => (
|
||||
const BackgroundContainer = ({ theme, text, loading }) => (
|
||||
<View style={styles.container}>
|
||||
<ImageBackground source={{ uri: `message_empty_${ theme }` }} style={styles.image} />
|
||||
<Text style={[styles.text, { color: themes[theme].auxiliaryTintColor }]}>{text}</Text>
|
||||
{text ? <Text style={[styles.text, { color: themes[theme].auxiliaryTintColor }]}>{text}</Text> : null}
|
||||
{loading ? <ActivityIndicator style={[styles.text, { color: themes[theme].auxiliaryTintColor }]} /> : null}
|
||||
</View>
|
||||
);
|
||||
|
||||
EmptyRoom.propTypes = {
|
||||
BackgroundContainer.propTypes = {
|
||||
text: PropTypes.string,
|
||||
theme: PropTypes.string
|
||||
theme: PropTypes.string,
|
||||
loading: PropTypes.bool
|
||||
};
|
||||
export default withTheme(EmptyRoom);
|
||||
export default withTheme(BackgroundContainer);
|
|
@ -0,0 +1,49 @@
|
|||
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions, react/prop-types */
|
||||
import React from 'react';
|
||||
import { storiesOf } from '@storybook/react-native';
|
||||
|
||||
import BackgroundContainer from '.';
|
||||
import { ThemeContext } from '../../theme';
|
||||
import { longText } from '../../../storybook/utils';
|
||||
|
||||
const stories = storiesOf('BackgroundContainer', module);
|
||||
|
||||
stories.add('basic', () => (
|
||||
<BackgroundContainer />
|
||||
));
|
||||
|
||||
stories.add('loading', () => (
|
||||
<BackgroundContainer loading />
|
||||
));
|
||||
|
||||
stories.add('text', () => (
|
||||
<BackgroundContainer text='Text here' />
|
||||
));
|
||||
|
||||
stories.add('long text', () => (
|
||||
<BackgroundContainer text={longText} />
|
||||
));
|
||||
|
||||
const ThemeStory = ({ theme, ...props }) => (
|
||||
<ThemeContext.Provider
|
||||
value={{ theme }}
|
||||
>
|
||||
<BackgroundContainer {...props} />
|
||||
</ThemeContext.Provider>
|
||||
);
|
||||
|
||||
stories.add('dark theme - loading', () => (
|
||||
<ThemeStory theme='dark' loading />
|
||||
));
|
||||
|
||||
stories.add('dark theme - text', () => (
|
||||
<ThemeStory theme='dark' text={longText} />
|
||||
));
|
||||
|
||||
stories.add('black theme - loading', () => (
|
||||
<ThemeStory theme='black' loading />
|
||||
));
|
||||
|
||||
stories.add('black theme - text', () => (
|
||||
<ThemeStory theme='black' text={longText} />
|
||||
));
|
|
@ -4,16 +4,21 @@ import {
|
|||
View, Text, StyleSheet, TouchableOpacity
|
||||
} from 'react-native';
|
||||
|
||||
import I18n from '../../../i18n';
|
||||
import sharedStyles from '../../Styles';
|
||||
import { themes } from '../../../constants/colors';
|
||||
import Markdown from '../../../containers/markdown';
|
||||
import RoomTypeIcon from '../../../containers/RoomTypeIcon';
|
||||
import I18n from '../../i18n';
|
||||
import sharedStyles from '../../views/Styles';
|
||||
import { themes } from '../../constants/colors';
|
||||
import Markdown from '../markdown';
|
||||
import RoomTypeIcon from '../RoomTypeIcon';
|
||||
import { withTheme } from '../../theme';
|
||||
|
||||
const HIT_SLOP = {
|
||||
top: 5, right: 5, bottom: 5, left: 5
|
||||
};
|
||||
const TITLE_SIZE = 16;
|
||||
const SUBTITLE_SIZE = 12;
|
||||
|
||||
const getSubTitleSize = scale => SUBTITLE_SIZE * scale;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
|
@ -24,12 +29,12 @@ const styles = StyleSheet.create({
|
|||
flexDirection: 'row'
|
||||
},
|
||||
title: {
|
||||
...sharedStyles.textSemibold,
|
||||
fontSize: TITLE_SIZE
|
||||
flexShrink: 1,
|
||||
...sharedStyles.textSemibold
|
||||
},
|
||||
subtitle: {
|
||||
...sharedStyles.textRegular,
|
||||
fontSize: 12
|
||||
flexShrink: 1,
|
||||
...sharedStyles.textRegular
|
||||
},
|
||||
typingUsers: {
|
||||
...sharedStyles.textSemibold
|
||||
|
@ -37,8 +42,9 @@ const styles = StyleSheet.create({
|
|||
});
|
||||
|
||||
const SubTitle = React.memo(({
|
||||
usersTyping, subtitle, renderFunc, theme
|
||||
usersTyping, subtitle, renderFunc, theme, scale
|
||||
}) => {
|
||||
const fontSize = getSubTitleSize(scale);
|
||||
// typing
|
||||
if (usersTyping.length) {
|
||||
let usersText;
|
||||
|
@ -48,7 +54,7 @@ const SubTitle = React.memo(({
|
|||
usersText = usersTyping.join(', ');
|
||||
}
|
||||
return (
|
||||
<Text style={[styles.subtitle, { color: themes[theme].auxiliaryText }]} numberOfLines={1}>
|
||||
<Text style={[styles.subtitle, { fontSize, color: themes[theme].auxiliaryText }]} numberOfLines={1}>
|
||||
<Text style={styles.typingUsers}>{usersText} </Text>
|
||||
{ usersTyping.length > 1 ? I18n.t('are_typing') : I18n.t('is_typing') }...
|
||||
</Text>
|
||||
|
@ -66,7 +72,7 @@ const SubTitle = React.memo(({
|
|||
<Markdown
|
||||
preview
|
||||
msg={subtitle}
|
||||
style={[styles.subtitle, { color: themes[theme].auxiliaryText }]}
|
||||
style={[styles.subtitle, { fontSize, color: themes[theme].auxiliaryText }]}
|
||||
numberOfLines={1}
|
||||
theme={theme}
|
||||
/>
|
||||
|
@ -80,18 +86,20 @@ SubTitle.propTypes = {
|
|||
usersTyping: PropTypes.array,
|
||||
theme: PropTypes.string,
|
||||
subtitle: PropTypes.string,
|
||||
renderFunc: PropTypes.func
|
||||
renderFunc: PropTypes.func,
|
||||
scale: PropTypes.number
|
||||
};
|
||||
|
||||
const HeaderTitle = React.memo(({
|
||||
title, tmid, prid, scale, theme
|
||||
title, tmid, prid, scale, theme, testID
|
||||
}) => {
|
||||
const titleStyle = { fontSize: TITLE_SIZE * scale, color: themes[theme].headerTitleColor };
|
||||
if (!tmid && !prid) {
|
||||
return (
|
||||
<Text
|
||||
style={[styles.title, { fontSize: TITLE_SIZE * scale, color: themes[theme].headerTitleColor }]}
|
||||
style={[styles.title, titleStyle]}
|
||||
numberOfLines={1}
|
||||
testID={`room-view-title-${ title }`}
|
||||
testID={testID}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
|
@ -102,10 +110,10 @@ const HeaderTitle = React.memo(({
|
|||
<Markdown
|
||||
preview
|
||||
msg={title}
|
||||
style={[styles.title, { fontSize: TITLE_SIZE * scale, color: themes[theme].headerTitleColor }]}
|
||||
style={[styles.title, titleStyle]}
|
||||
numberOfLines={1}
|
||||
theme={theme}
|
||||
testID={`room-view-title-${ title }`}
|
||||
testID={testID}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
@ -115,11 +123,12 @@ HeaderTitle.propTypes = {
|
|||
tmid: PropTypes.string,
|
||||
prid: PropTypes.string,
|
||||
scale: PropTypes.number,
|
||||
theme: PropTypes.string
|
||||
theme: PropTypes.string,
|
||||
testID: PropTypes.string
|
||||
};
|
||||
|
||||
const Header = React.memo(({
|
||||
title, subtitle, parentTitle, type, status, usersTyping, width, height, prid, tmid, connecting, goRoomActionsView, theme, isGroupChat
|
||||
title, subtitle, parentTitle, type, status, usersTyping, width, height, prid, tmid, onPress, theme, isGroupChat, teamMain, testID
|
||||
}) => {
|
||||
const portrait = height > width;
|
||||
let scale = 1;
|
||||
|
@ -130,13 +139,11 @@ const Header = React.memo(({
|
|||
}
|
||||
}
|
||||
|
||||
const onPress = () => goRoomActionsView();
|
||||
|
||||
let renderFunc;
|
||||
if (tmid) {
|
||||
renderFunc = () => (
|
||||
<View style={styles.titleContainer}>
|
||||
<RoomTypeIcon type={prid ? 'discussion' : type} isGroupChat={isGroupChat} status={status} />
|
||||
<RoomTypeIcon type={prid ? 'discussion' : type} isGroupChat={isGroupChat} status={status} teamMain={teamMain} />
|
||||
<Text style={[styles.subtitle, { color: themes[theme].auxiliaryText }]} numberOfLines={1}>{parentTitle}</Text>
|
||||
</View>
|
||||
);
|
||||
|
@ -144,7 +151,7 @@ const Header = React.memo(({
|
|||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
testID='room-view-header-actions'
|
||||
testID='room-header'
|
||||
accessibilityLabel={title}
|
||||
onPress={onPress}
|
||||
style={styles.container}
|
||||
|
@ -152,17 +159,23 @@ const Header = React.memo(({
|
|||
hitSlop={HIT_SLOP}
|
||||
>
|
||||
<View style={styles.titleContainer}>
|
||||
{tmid ? null : <RoomTypeIcon type={prid ? 'discussion' : type} isGroupChat={isGroupChat} status={status} />}
|
||||
{tmid ? null : <RoomTypeIcon type={prid ? 'discussion' : type} isGroupChat={isGroupChat} status={status} teamMain={teamMain} />}
|
||||
<HeaderTitle
|
||||
title={title}
|
||||
tmid={tmid}
|
||||
prid={prid}
|
||||
scale={scale}
|
||||
connecting={connecting}
|
||||
theme={theme}
|
||||
testID={testID}
|
||||
/>
|
||||
</View>
|
||||
<SubTitle usersTyping={tmid ? [] : usersTyping} subtitle={subtitle} theme={theme} renderFunc={renderFunc} />
|
||||
<SubTitle
|
||||
usersTyping={tmid ? [] : usersTyping}
|
||||
subtitle={subtitle}
|
||||
theme={theme}
|
||||
renderFunc={renderFunc}
|
||||
scale={scale}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
});
|
||||
|
@ -175,17 +188,18 @@ Header.propTypes = {
|
|||
height: PropTypes.number.isRequired,
|
||||
prid: PropTypes.string,
|
||||
tmid: PropTypes.string,
|
||||
teamMain: PropTypes.bool,
|
||||
status: PropTypes.string,
|
||||
theme: PropTypes.string,
|
||||
usersTyping: PropTypes.array,
|
||||
connecting: PropTypes.bool,
|
||||
isGroupChat: PropTypes.bool,
|
||||
parentTitle: PropTypes.string,
|
||||
goRoomActionsView: PropTypes.func
|
||||
onPress: PropTypes.func,
|
||||
testID: PropTypes.string
|
||||
};
|
||||
|
||||
Header.defaultProps = {
|
||||
usersTyping: []
|
||||
};
|
||||
|
||||
export default Header;
|
||||
export default withTheme(Header);
|
|
@ -0,0 +1,94 @@
|
|||
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions, react/prop-types, react/destructuring-assignment */
|
||||
import React from 'react';
|
||||
import { View, Dimensions } from 'react-native';
|
||||
import { storiesOf } from '@storybook/react-native';
|
||||
|
||||
import RoomHeaderComponent from './RoomHeader';
|
||||
import Header from '../Header';
|
||||
import { longText } from '../../../storybook/utils';
|
||||
import { ThemeContext } from '../../theme';
|
||||
|
||||
const stories = storiesOf('RoomHeader', module);
|
||||
|
||||
// TODO: refactor after react-navigation v6
|
||||
const HeaderExample = ({ title }) => (
|
||||
<Header
|
||||
headerTitle={() => (
|
||||
<View style={{ flex: 1, paddingHorizontal: 12 }}>
|
||||
{title()}
|
||||
</View>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
||||
const { width, height } = Dimensions.get('window');
|
||||
|
||||
const RoomHeader = ({ ...props }) => (
|
||||
<RoomHeaderComponent width={width} height={height} title='title' type='p' testID={props.title} onPress={() => alert('header pressed!')} {...props} />
|
||||
);
|
||||
|
||||
stories.add('title and subtitle', () => (
|
||||
<>
|
||||
<HeaderExample title={() => <RoomHeader title='title' type='p' />} />
|
||||
<HeaderExample title={() => <RoomHeader title={longText} type='p' />} />
|
||||
<HeaderExample title={() => <RoomHeader subtitle='subtitle' />} />
|
||||
<HeaderExample title={() => <RoomHeader subtitle={longText} />} />
|
||||
<HeaderExample title={() => <RoomHeader title={longText} subtitle={longText} />} />
|
||||
</>
|
||||
));
|
||||
|
||||
stories.add('icons', () => (
|
||||
<>
|
||||
<HeaderExample title={() => <RoomHeader title='private channel' type='p' />} />
|
||||
<HeaderExample title={() => <RoomHeader title='public channel' type='c' />} />
|
||||
<HeaderExample title={() => <RoomHeader title='discussion' prid='asd' />} />
|
||||
<HeaderExample title={() => <RoomHeader title='omnichannel' type='l' />} />
|
||||
<HeaderExample title={() => <RoomHeader title='private team' type='p' teamMain />} />
|
||||
<HeaderExample title={() => <RoomHeader title='public team' type='c' teamMain />} />
|
||||
<HeaderExample title={() => <RoomHeader title='group dm' type='d' isGroupChat />} />
|
||||
<HeaderExample title={() => <RoomHeader title='online dm' type='d' status='online' />} />
|
||||
<HeaderExample title={() => <RoomHeader title='away dm' type='d' status='away' />} />
|
||||
<HeaderExample title={() => <RoomHeader title='busy dm' type='d' status='busy' />} />
|
||||
<HeaderExample title={() => <RoomHeader title='loading dm' type='d' status='loading' />} />
|
||||
<HeaderExample title={() => <RoomHeader title='offline dm' type='d' />} />
|
||||
</>
|
||||
));
|
||||
|
||||
stories.add('typing', () => (
|
||||
<>
|
||||
<HeaderExample title={() => <RoomHeader usersTyping={['user 1']} />} />
|
||||
<HeaderExample title={() => <RoomHeader usersTyping={['user 1', 'user 2']} />} />
|
||||
<HeaderExample title={() => <RoomHeader usersTyping={['user 1', 'user 2', 'user 3', 'user 4', 'user 5']} />} />
|
||||
</>
|
||||
));
|
||||
|
||||
stories.add('landscape', () => (
|
||||
<>
|
||||
<HeaderExample title={() => <RoomHeader width={height} height={width} />} />
|
||||
<HeaderExample title={() => <RoomHeader width={height} height={width} subtitle='subtitle' />} />
|
||||
<HeaderExample title={() => <RoomHeader width={height} height={width} title={longText} subtitle={longText} />} />
|
||||
</>
|
||||
));
|
||||
|
||||
stories.add('thread', () => (
|
||||
<>
|
||||
<HeaderExample title={() => <RoomHeader tmid='123' parentTitle='parent title' />} />
|
||||
<HeaderExample title={() => <RoomHeader tmid='123' title={'markdown\npreview\n#3\n4\n5'} parentTitle={longText} />} />
|
||||
</>
|
||||
));
|
||||
|
||||
const ThemeStory = ({ theme }) => (
|
||||
<ThemeContext.Provider
|
||||
value={{ theme }}
|
||||
>
|
||||
<HeaderExample title={() => <RoomHeader subtitle='subtitle' />} />
|
||||
</ThemeContext.Provider>
|
||||
);
|
||||
|
||||
stories.add('themes', () => (
|
||||
<>
|
||||
<ThemeStory theme='light' />
|
||||
<ThemeStory theme='dark' />
|
||||
<ThemeStory theme='black' />
|
||||
</>
|
||||
));
|
|
@ -3,42 +3,37 @@ import PropTypes from 'prop-types';
|
|||
import { connect } from 'react-redux';
|
||||
import { dequal } from 'dequal';
|
||||
|
||||
import Header from './Header';
|
||||
import LeftButtons from './LeftButtons';
|
||||
import RightButtons from './RightButtons';
|
||||
import { withTheme } from '../../../theme';
|
||||
import { withDimensions } from '../../../dimensions';
|
||||
import I18n from '../../../i18n';
|
||||
import RoomHeader from './RoomHeader';
|
||||
import { withDimensions } from '../../dimensions';
|
||||
import I18n from '../../i18n';
|
||||
|
||||
class RoomHeaderView extends Component {
|
||||
class RoomHeaderContainer extends Component {
|
||||
static propTypes = {
|
||||
title: PropTypes.string,
|
||||
subtitle: PropTypes.string,
|
||||
type: PropTypes.string,
|
||||
prid: PropTypes.string,
|
||||
tmid: PropTypes.string,
|
||||
teamMain: PropTypes.bool,
|
||||
usersTyping: PropTypes.string,
|
||||
status: PropTypes.string,
|
||||
statusText: PropTypes.string,
|
||||
connecting: PropTypes.bool,
|
||||
connected: PropTypes.bool,
|
||||
theme: PropTypes.string,
|
||||
roomUserId: PropTypes.string,
|
||||
widthOffset: PropTypes.number,
|
||||
goRoomActionsView: PropTypes.func,
|
||||
onPress: PropTypes.func,
|
||||
width: PropTypes.number,
|
||||
height: PropTypes.number,
|
||||
parentTitle: PropTypes.string,
|
||||
isGroupChat: PropTypes.bool
|
||||
isGroupChat: PropTypes.bool,
|
||||
testID: PropTypes.string
|
||||
};
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
const {
|
||||
type, title, subtitle, status, statusText, connecting, connected, goRoomActionsView, usersTyping, theme, width, height
|
||||
type, title, subtitle, status, statusText, connecting, connected, onPress, usersTyping, width, height
|
||||
} = this.props;
|
||||
if (nextProps.theme !== theme) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.type !== type) {
|
||||
return true;
|
||||
}
|
||||
|
@ -69,7 +64,7 @@ class RoomHeaderView extends Component {
|
|||
if (!dequal(nextProps.usersTyping, usersTyping)) {
|
||||
return true;
|
||||
}
|
||||
if (nextProps.goRoomActionsView !== goRoomActionsView) {
|
||||
if (nextProps.onPress !== onPress) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -80,6 +75,7 @@ class RoomHeaderView extends Component {
|
|||
title,
|
||||
subtitle: subtitleProp,
|
||||
type,
|
||||
teamMain,
|
||||
prid,
|
||||
tmid,
|
||||
widthOffset,
|
||||
|
@ -88,13 +84,13 @@ class RoomHeaderView extends Component {
|
|||
connecting,
|
||||
connected,
|
||||
usersTyping,
|
||||
goRoomActionsView,
|
||||
onPress,
|
||||
roomUserId,
|
||||
theme,
|
||||
width,
|
||||
height,
|
||||
parentTitle,
|
||||
isGroupChat
|
||||
isGroupChat,
|
||||
testID
|
||||
} = this.props;
|
||||
|
||||
let subtitle;
|
||||
|
@ -107,23 +103,24 @@ class RoomHeaderView extends Component {
|
|||
}
|
||||
|
||||
return (
|
||||
<Header
|
||||
<RoomHeader
|
||||
prid={prid}
|
||||
tmid={tmid}
|
||||
title={title}
|
||||
subtitle={type === 'd' ? statusText : subtitle}
|
||||
type={type}
|
||||
teamMain={teamMain}
|
||||
status={status}
|
||||
width={width}
|
||||
height={height}
|
||||
theme={theme}
|
||||
usersTyping={usersTyping}
|
||||
widthOffset={widthOffset}
|
||||
roomUserId={roomUserId}
|
||||
goRoomActionsView={goRoomActionsView}
|
||||
connecting={connecting}
|
||||
parentTitle={parentTitle}
|
||||
isGroupChat={isGroupChat}
|
||||
testID={testID}
|
||||
onPress={onPress}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -153,6 +150,4 @@ const mapStateToProps = (state, ownProps) => {
|
|||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(withDimensions(withTheme(RoomHeaderView)));
|
||||
|
||||
export { RightButtons, LeftButtons };
|
||||
export default connect(mapStateToProps)(withDimensions(RoomHeaderContainer));
|
|
@ -13,7 +13,7 @@ const styles = StyleSheet.create({
|
|||
});
|
||||
|
||||
const RoomTypeIcon = React.memo(({
|
||||
type, size, isGroupChat, status, style, theme
|
||||
type, size, isGroupChat, status, style, theme, teamMain
|
||||
}) => {
|
||||
if (!type) {
|
||||
return null;
|
||||
|
@ -31,7 +31,9 @@ const RoomTypeIcon = React.memo(({
|
|||
}
|
||||
|
||||
let icon = 'channel-private';
|
||||
if (type === 'discussion') {
|
||||
if (teamMain) {
|
||||
icon = `teams${ type === 'p' ? '-private' : '' }`;
|
||||
} else if (type === 'discussion') {
|
||||
icon = 'discussions';
|
||||
} else if (type === 'c') {
|
||||
icon = 'channel-public';
|
||||
|
@ -58,6 +60,7 @@ RoomTypeIcon.propTypes = {
|
|||
theme: PropTypes.string,
|
||||
type: PropTypes.string,
|
||||
isGroupChat: PropTypes.bool,
|
||||
teamMain: PropTypes.bool,
|
||||
status: PropTypes.string,
|
||||
size: PropTypes.number,
|
||||
style: PropTypes.object
|
||||
|
|
|
@ -706,5 +706,8 @@
|
|||
"Enter_workspace_URL": "Enter workspace URL",
|
||||
"Workspace_URL_Example": "Ex. your-company.rocket.chat",
|
||||
"This_room_encryption_has_been_enabled_by__username_": "This room's encryption has been enabled by {{username}}",
|
||||
"This_room_encryption_has_been_disabled_by__username_": "This room's encryption has been disabled by {{username}}"
|
||||
"This_room_encryption_has_been_disabled_by__username_": "This room's encryption has been disabled by {{username}}",
|
||||
"Teams": "Teams",
|
||||
"No_team_channels_found": "No channels found",
|
||||
"Team_not_found": "Team not found"
|
||||
}
|
|
@ -656,5 +656,8 @@
|
|||
"This_room_encryption_has_been_disabled_by__username_": "A criptografia para essa sala foi desabilitada por {{username}}",
|
||||
"Apply_Your_Certificate": "Aplicar certificado",
|
||||
"Do_you_have_a_certificate": "Você tem um certificado?",
|
||||
"Your_certificate": "Seu certificado"
|
||||
"Your_certificate": "Seu certificado",
|
||||
"Teams": "Times",
|
||||
"No_team_channels_found": "Nenhum canal encontrado",
|
||||
"Team_not_found": "Time não encontrado"
|
||||
}
|
|
@ -125,4 +125,8 @@ export default class Subscription extends Model {
|
|||
@field('e2e_key_id') e2eKeyId;
|
||||
|
||||
@field('avatar_etag') avatarETag;
|
||||
|
||||
@field('team_id') teamId;
|
||||
|
||||
@field('team_main') teamMain;
|
||||
}
|
||||
|
|
|
@ -212,6 +212,18 @@ export default schemaMigrations({
|
|||
]
|
||||
})
|
||||
]
|
||||
},
|
||||
{
|
||||
toVersion: 13,
|
||||
steps: [
|
||||
addColumns({
|
||||
table: 'subscriptions',
|
||||
columns: [
|
||||
{ name: 'team_id', type: 'string', isIndexed: true },
|
||||
{ name: 'team_main', type: 'boolean', isOptional: true }
|
||||
]
|
||||
})
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { appSchema, tableSchema } from '@nozbe/watermelondb';
|
||||
|
||||
export default appSchema({
|
||||
version: 12,
|
||||
version: 13,
|
||||
tables: [
|
||||
tableSchema({
|
||||
name: 'subscriptions',
|
||||
|
@ -57,7 +57,9 @@ export default appSchema({
|
|||
{ name: 'e2e_key', type: 'string', isOptional: true },
|
||||
{ name: 'encrypted', type: 'boolean', isOptional: true },
|
||||
{ name: 'e2e_key_id', type: 'string', isOptional: true },
|
||||
{ name: 'avatar_etag', type: 'string', isOptional: true }
|
||||
{ name: 'avatar_etag', type: 'string', isOptional: true },
|
||||
{ name: 'team_id', type: 'string', isIndexed: true },
|
||||
{ name: 'team_main', type: 'boolean', isOptional: true }
|
||||
]
|
||||
}),
|
||||
tableSchema({
|
||||
|
|
|
@ -42,6 +42,8 @@ export const merge = (subscription, room) => {
|
|||
subscription.encrypted = room.encrypted;
|
||||
subscription.e2eKeyId = room.e2eKeyId;
|
||||
subscription.avatarETag = room.avatarETag;
|
||||
subscription.teamId = room.teamId;
|
||||
subscription.teamMain = room.teamMain;
|
||||
if (!subscription.roles || !subscription.roles.length) {
|
||||
subscription.roles = [];
|
||||
}
|
||||
|
|
|
@ -931,6 +931,19 @@ const RocketChat = {
|
|||
// RC 2.3.0
|
||||
return this.sdk.get('livechat/visitors.info', { visitorId });
|
||||
},
|
||||
getTeamListRoom({
|
||||
teamId, count, offset, type, filter
|
||||
}) {
|
||||
const params = {
|
||||
teamId, count, offset, type
|
||||
};
|
||||
|
||||
if (filter) {
|
||||
params.filter = filter;
|
||||
}
|
||||
// RC 3.13.0
|
||||
return this.sdk.get('teams.listRooms', params);
|
||||
},
|
||||
closeLivechat(rid, comment) {
|
||||
// RC 0.29.0
|
||||
return this.methodCallWrapper('livechat:closeRoom', rid, comment, { clientAction: true });
|
||||
|
|
|
@ -44,7 +44,8 @@ const RoomItem = ({
|
|||
onPress,
|
||||
toggleFav,
|
||||
toggleRead,
|
||||
hideChannel
|
||||
hideChannel,
|
||||
teamMain
|
||||
}) => (
|
||||
<Touchable
|
||||
onPress={onPress}
|
||||
|
@ -78,6 +79,8 @@ const RoomItem = ({
|
|||
prid={prid}
|
||||
status={status}
|
||||
isGroupChat={isGroupChat}
|
||||
theme={theme}
|
||||
teamMain={teamMain}
|
||||
/>
|
||||
<Title
|
||||
name={name}
|
||||
|
@ -120,6 +123,8 @@ const RoomItem = ({
|
|||
prid={prid}
|
||||
status={status}
|
||||
isGroupChat={isGroupChat}
|
||||
theme={theme}
|
||||
teamMain={teamMain}
|
||||
/>
|
||||
<Title
|
||||
name={name}
|
||||
|
@ -159,6 +164,7 @@ RoomItem.propTypes = {
|
|||
isFocused: PropTypes.bool,
|
||||
isGroupChat: PropTypes.bool,
|
||||
isRead: PropTypes.bool,
|
||||
teamMain: PropTypes.bool,
|
||||
date: PropTypes.string,
|
||||
accessibilityLabel: PropTypes.string,
|
||||
lastMessage: PropTypes.object,
|
||||
|
|
|
@ -4,14 +4,15 @@ import PropTypes from 'prop-types';
|
|||
import RoomTypeIcon from '../../containers/RoomTypeIcon';
|
||||
|
||||
const TypeIcon = React.memo(({
|
||||
type, prid, status, isGroupChat
|
||||
}) => <RoomTypeIcon type={prid ? 'discussion' : type} isGroupChat={isGroupChat} status={status} />);
|
||||
type, prid, status, isGroupChat, teamMain
|
||||
}) => <RoomTypeIcon type={prid ? 'discussion' : type} isGroupChat={isGroupChat} status={status} teamMain={teamMain} />);
|
||||
|
||||
TypeIcon.propTypes = {
|
||||
type: PropTypes.string,
|
||||
status: PropTypes.string,
|
||||
prid: PropTypes.string,
|
||||
isGroupChat: PropTypes.bool
|
||||
isGroupChat: PropTypes.bool,
|
||||
teamMain: PropTypes.bool
|
||||
};
|
||||
|
||||
export default TypeIcon;
|
||||
|
|
|
@ -188,6 +188,7 @@ class RoomItemContainer extends React.Component {
|
|||
tunreadUser={item.tunreadUser}
|
||||
tunreadGroup={item.tunreadGroup}
|
||||
swipeEnabled={swipeEnabled}
|
||||
teamMain={item.teamMain}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import mergeSubscriptionsRooms from '../lib/methods/helpers/mergeSubscriptionsRo
|
|||
import RocketChat from '../lib/rocketchat';
|
||||
import buildMessage from '../lib/methods/helpers/buildMessage';
|
||||
import protectedFunction from '../lib/methods/helpers/protectedFunction';
|
||||
import UserPreferences from '../lib/userPreferences';
|
||||
|
||||
const updateRooms = function* updateRooms({ server, newRoomsUpdatedAt }) {
|
||||
const serversDB = database.servers;
|
||||
|
@ -47,6 +48,16 @@ const handleRoomsRequest = function* handleRoomsRequest({ params }) {
|
|||
// Server not found
|
||||
}
|
||||
}
|
||||
|
||||
// Force fetch all subscriptions to update columns related to Teams feature
|
||||
// TODO: remove it a couple of releases
|
||||
const teamsMigrationKey = `${ server }_TEAMS_MIGRATION`;
|
||||
const teamsMigration = yield UserPreferences.getBoolAsync(teamsMigrationKey);
|
||||
if (!teamsMigration) {
|
||||
roomsUpdatedAt = null;
|
||||
UserPreferences.setBoolAsync(teamsMigrationKey, true);
|
||||
}
|
||||
|
||||
const [subscriptionsResult, roomsResult] = yield RocketChat.getRooms(roomsUpdatedAt);
|
||||
const { subscriptions } = yield mergeSubscriptionsRooms(subscriptionsResult, roomsResult);
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ import ForwardLivechatView from '../views/ForwardLivechatView';
|
|||
import LivechatEditView from '../views/LivechatEditView';
|
||||
import PickerView from '../views/PickerView';
|
||||
import ThreadMessagesView from '../views/ThreadMessagesView';
|
||||
import TeamChannelsView from '../views/TeamChannelsView';
|
||||
import MarkdownTableView from '../views/MarkdownTableView';
|
||||
import ReadReceiptsView from '../views/ReadReceiptView';
|
||||
import { themes } from '../constants/colors';
|
||||
|
@ -168,6 +169,11 @@ const ChatsStackNavigator = () => {
|
|||
component={ThreadMessagesView}
|
||||
options={ThreadMessagesView.navigationOptions}
|
||||
/>
|
||||
<ChatsStack.Screen
|
||||
name='TeamChannelsView'
|
||||
component={TeamChannelsView}
|
||||
options={TeamChannelsView.navigationOptions}
|
||||
/>
|
||||
<ChatsStack.Screen
|
||||
name='MarkdownTableView'
|
||||
component={MarkdownTableView}
|
||||
|
|
|
@ -30,6 +30,7 @@ import ForwardLivechatView from '../../views/ForwardLivechatView';
|
|||
import LivechatEditView from '../../views/LivechatEditView';
|
||||
import PickerView from '../../views/PickerView';
|
||||
import ThreadMessagesView from '../../views/ThreadMessagesView';
|
||||
import TeamChannelsView from '../../views/TeamChannelsView';
|
||||
import MarkdownTableView from '../../views/MarkdownTableView';
|
||||
import ReadReceiptsView from '../../views/ReadReceiptView';
|
||||
import ProfileView from '../../views/ProfileView';
|
||||
|
@ -193,6 +194,11 @@ const ModalStackNavigator = React.memo(({ navigation }) => {
|
|||
name='ThreadMessagesView'
|
||||
component={ThreadMessagesView}
|
||||
/>
|
||||
<ModalStack.Screen
|
||||
name='TeamChannelsView'
|
||||
component={TeamChannelsView}
|
||||
options={TeamChannelsView.navigationOptions}
|
||||
/>
|
||||
<ModalStack.Screen
|
||||
name='MarkdownTableView'
|
||||
component={MarkdownTableView}
|
||||
|
|
|
@ -2,7 +2,7 @@ import Navigation from '../lib/Navigation';
|
|||
import RocketChat from '../lib/rocketchat';
|
||||
|
||||
const navigate = ({ item, isMasterDetail, ...props }) => {
|
||||
let navigationMethod = Navigation.navigate;
|
||||
let navigationMethod = props.navigationMethod ?? Navigation.navigate;
|
||||
|
||||
if (isMasterDetail) {
|
||||
navigationMethod = Navigation.replace;
|
||||
|
|
|
@ -212,6 +212,7 @@ export default {
|
|||
ROOM_JOIN: 'room_join',
|
||||
ROOM_GO_RA: 'room_go_ra',
|
||||
ROOM_TOGGLE_FOLLOW_THREADS: 'room_toggle_follow_threads',
|
||||
ROOM_GO_TEAM_CHANNELS: 'room_go_team_channels',
|
||||
ROOM_GO_SEARCH: 'room_go_search',
|
||||
ROOM_GO_THREADS: 'room_go_threads',
|
||||
ROOM_GO_ROOM_INFO: 'room_go_room_info',
|
||||
|
@ -310,5 +311,11 @@ export default {
|
|||
|
||||
// E2E ENCRYPTION SECURITY VIEW
|
||||
E2E_SEC_CHANGE_PASSWORD: 'e2e_sec_change_password',
|
||||
E2E_SEC_RESET_OWN_KEY: 'e2e_sec_reset_own_key'
|
||||
E2E_SEC_RESET_OWN_KEY: 'e2e_sec_reset_own_key',
|
||||
|
||||
// TEAM CHANNELS VIEW
|
||||
TC_SEARCH: 'tc_search',
|
||||
TC_CANCEL_SEARCH: 'tc_cancel_search',
|
||||
TC_GO_ACTIONS: 'tc_go_actions',
|
||||
TC_GO_ROOM: 'tc_go_room'
|
||||
};
|
||||
|
|
|
@ -175,7 +175,7 @@ class NewMessageView extends React.Component {
|
|||
{maxUsers > 2 ? this.renderButton({
|
||||
onPress: this.createGroupChat,
|
||||
title: I18n.t('Create_Direct_Messages'),
|
||||
icon: 'team',
|
||||
icon: 'message',
|
||||
testID: 'new-message-view-create-direct-message'
|
||||
}) : null}
|
||||
{this.renderButton({
|
||||
|
|
|
@ -461,7 +461,7 @@ class RoomActionsView extends React.Component {
|
|||
? <Text style={[styles.roomTitle, { color: themes[theme].titleText }]} numberOfLines={1}>{room.fname}</Text>
|
||||
: (
|
||||
<View style={styles.roomTitleRow}>
|
||||
<RoomTypeIcon type={room.prid ? 'discussion' : room.t} status={room.visitor?.status} />
|
||||
<RoomTypeIcon type={room.prid ? 'discussion' : room.t} teamMain={room.teamMain} status={room.visitor?.status} />
|
||||
<Text style={[styles.roomTitle, { color: themes[theme].titleText }]} numberOfLines={1}>{RocketChat.getRoomTitle(room)}</Text>
|
||||
</View>
|
||||
)
|
||||
|
|
|
@ -41,7 +41,7 @@ const getRoomTitle = (room, type, name, username, statusText, theme) => (type ==
|
|||
)
|
||||
: (
|
||||
<View style={styles.roomTitleRow}>
|
||||
<RoomTypeIcon type={room.prid ? 'discussion' : room.t} key='room-info-type' status={room.visitor?.status} />
|
||||
<RoomTypeIcon type={room.prid ? 'discussion' : room.t} teamMain={room.teamMain} key='room-info-type' status={room.visitor?.status} />
|
||||
<Text testID='room-info-view-name' style={[styles.roomTitle, { color: themes[theme].titleText }]} key='room-info-name'>{RocketChat.getRoomTitle(room)}</Text>
|
||||
</View>
|
||||
)
|
||||
|
|
|
@ -3,8 +3,8 @@ import PropTypes from 'prop-types';
|
|||
import { StyleSheet } from 'react-native';
|
||||
import { HeaderBackButton } from '@react-navigation/stack';
|
||||
|
||||
import { themes } from '../../../constants/colors';
|
||||
import Avatar from '../../../containers/Avatar';
|
||||
import { themes } from '../../constants/colors';
|
||||
import Avatar from '../../containers/Avatar';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
avatar: {
|
|
@ -3,10 +3,10 @@ import PropTypes from 'prop-types';
|
|||
import { connect } from 'react-redux';
|
||||
import { dequal } from 'dequal';
|
||||
|
||||
import * as HeaderButton from '../../../containers/HeaderButton';
|
||||
import database from '../../../lib/database';
|
||||
import { getUserSelector } from '../../../selectors/login';
|
||||
import { logEvent, events } from '../../../utils/log';
|
||||
import * as HeaderButton from '../../containers/HeaderButton';
|
||||
import database from '../../lib/database';
|
||||
import { getUserSelector } from '../../selectors/login';
|
||||
import { logEvent, events } from '../../utils/log';
|
||||
|
||||
class RightButtonsContainer extends Component {
|
||||
static propTypes = {
|
||||
|
@ -15,6 +15,7 @@ class RightButtonsContainer extends Component {
|
|||
rid: PropTypes.string,
|
||||
t: PropTypes.string,
|
||||
tmid: PropTypes.string,
|
||||
teamId: PropTypes.bool,
|
||||
navigation: PropTypes.object,
|
||||
isMasterDetail: PropTypes.bool,
|
||||
toggleFollowThread: PropTypes.func
|
||||
|
@ -109,6 +110,21 @@ class RightButtonsContainer extends Component {
|
|||
});
|
||||
}
|
||||
|
||||
goTeamChannels = () => {
|
||||
logEvent(events.ROOM_GO_TEAM_CHANNELS);
|
||||
const {
|
||||
navigation, isMasterDetail, teamId
|
||||
} = this.props;
|
||||
if (isMasterDetail) {
|
||||
navigation.navigate('ModalStackNavigator', {
|
||||
screen: 'TeamChannelsView',
|
||||
params: { teamId }
|
||||
});
|
||||
} else {
|
||||
navigation.navigate('TeamChannelsView', { teamId });
|
||||
}
|
||||
}
|
||||
|
||||
goThreadsView = () => {
|
||||
logEvent(events.ROOM_GO_THREADS);
|
||||
const {
|
||||
|
@ -146,7 +162,9 @@ class RightButtonsContainer extends Component {
|
|||
const {
|
||||
isFollowingThread, tunread, tunreadUser, tunreadGroup
|
||||
} = this.state;
|
||||
const { t, tmid, threadsEnabled } = this.props;
|
||||
const {
|
||||
t, tmid, threadsEnabled, teamId
|
||||
} = this.props;
|
||||
if (t === 'l') {
|
||||
return null;
|
||||
}
|
||||
|
@ -163,6 +181,13 @@ class RightButtonsContainer extends Component {
|
|||
}
|
||||
return (
|
||||
<HeaderButton.Container>
|
||||
{teamId ? (
|
||||
<HeaderButton.Item
|
||||
iconName='channel-public'
|
||||
onPress={this.goTeamChannels}
|
||||
testID='room-view-header-team-channels'
|
||||
/>
|
||||
) : null}
|
||||
{threadsEnabled ? (
|
||||
<HeaderButton.Item
|
||||
iconName='threads'
|
|
@ -29,7 +29,9 @@ import styles from './styles';
|
|||
import log, { logEvent, events } from '../../utils/log';
|
||||
import EventEmitter from '../../utils/events';
|
||||
import I18n from '../../i18n';
|
||||
import RoomHeaderView, { RightButtons, LeftButtons } from './Header';
|
||||
import RoomHeader from '../../containers/RoomHeader';
|
||||
import LeftButtons from './LeftButtons';
|
||||
import RightButtons from './RightButtons';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
import Separator from './Separator';
|
||||
import { themes } from '../../constants/colors';
|
||||
|
@ -317,13 +319,23 @@ class RoomView extends React.Component {
|
|||
}
|
||||
const subtitle = room?.topic;
|
||||
const t = room?.t;
|
||||
const teamMain = room?.teamMain;
|
||||
const teamId = room?.teamId;
|
||||
const { id: userId, token } = user;
|
||||
const avatar = room?.name;
|
||||
const visitor = room?.visitor;
|
||||
if (!room?.rid) {
|
||||
return;
|
||||
}
|
||||
const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight: tmid ? 1 : 2 });
|
||||
|
||||
let numIconsRight = 2;
|
||||
if (tmid) {
|
||||
numIconsRight = 1;
|
||||
} else if (teamId) {
|
||||
numIconsRight = 3;
|
||||
}
|
||||
const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight });
|
||||
|
||||
navigation.setOptions({
|
||||
headerShown: true,
|
||||
headerTitleAlign: 'left',
|
||||
|
@ -347,24 +359,27 @@ class RoomView extends React.Component {
|
|||
/>
|
||||
),
|
||||
headerTitle: () => (
|
||||
<RoomHeaderView
|
||||
<RoomHeader
|
||||
rid={rid}
|
||||
prid={prid}
|
||||
tmid={tmid}
|
||||
title={title}
|
||||
teamMain={teamMain}
|
||||
parentTitle={parentTitle}
|
||||
subtitle={subtitle}
|
||||
type={t}
|
||||
roomUserId={roomUserId}
|
||||
visitor={visitor}
|
||||
isGroupChat={isGroupChat}
|
||||
goRoomActionsView={this.goRoomActionsView}
|
||||
onPress={this.goRoomActionsView}
|
||||
testID={`room-view-title-${ title }`}
|
||||
/>
|
||||
),
|
||||
headerRight: () => (
|
||||
<RightButtons
|
||||
rid={rid}
|
||||
tmid={tmid}
|
||||
teamId={teamId}
|
||||
t={t}
|
||||
navigation={navigation}
|
||||
toggleFollowThread={this.toggleFollowThread}
|
||||
|
|
|
@ -68,6 +68,7 @@ const CHATS_HEADER = 'Chats';
|
|||
const UNREAD_HEADER = 'Unread';
|
||||
const FAVORITES_HEADER = 'Favorites';
|
||||
const DISCUSSIONS_HEADER = 'Discussions';
|
||||
const TEAMS_HEADER = 'Teams';
|
||||
const CHANNELS_HEADER = 'Channels';
|
||||
const DM_HEADER = 'Direct_Messages';
|
||||
const GROUPS_HEADER = 'Private_Groups';
|
||||
|
@ -77,6 +78,8 @@ const QUERY_SIZE = 20;
|
|||
const filterIsUnread = s => (s.unread > 0 || s.tunread?.length > 0 || s.alert) && !s.hideUnreadStatus;
|
||||
const filterIsFavorite = s => s.f;
|
||||
const filterIsOmnichannel = s => s.t === 'l';
|
||||
const filterIsTeam = s => s.teamMain;
|
||||
const filterIsDiscussion = s => s.prid;
|
||||
|
||||
const shouldUpdateProps = [
|
||||
'searchText',
|
||||
|
@ -475,10 +478,12 @@ class RoomsListView extends React.Component {
|
|||
|
||||
// type
|
||||
if (groupByType) {
|
||||
const discussions = chats.filter(s => s.prid);
|
||||
const channels = chats.filter(s => s.t === 'c' && !s.prid);
|
||||
const privateGroup = chats.filter(s => s.t === 'p' && !s.prid);
|
||||
const direct = chats.filter(s => s.t === 'd' && !s.prid);
|
||||
const teams = chats.filter(s => filterIsTeam(s));
|
||||
const discussions = chats.filter(s => filterIsDiscussion(s));
|
||||
const channels = chats.filter(s => s.t === 'c' && !filterIsDiscussion(s) && !filterIsTeam(s));
|
||||
const privateGroup = chats.filter(s => s.t === 'p' && !filterIsDiscussion(s) && !filterIsTeam(s));
|
||||
const direct = chats.filter(s => s.t === 'd' && !filterIsDiscussion(s) && !filterIsTeam(s));
|
||||
tempChats = this.addRoomsGroup(teams, TEAMS_HEADER, tempChats);
|
||||
tempChats = this.addRoomsGroup(discussions, DISCUSSIONS_HEADER, tempChats);
|
||||
tempChats = this.addRoomsGroup(channels, CHANNELS_HEADER, tempChats);
|
||||
tempChats = this.addRoomsGroup(privateGroup, GROUPS_HEADER, tempChats);
|
||||
|
|
|
@ -0,0 +1,369 @@
|
|||
import React from 'react';
|
||||
import { Keyboard } from 'react-native';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Q } from '@nozbe/watermelondb';
|
||||
import { withSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { connect } from 'react-redux';
|
||||
import { FlatList } from 'react-native-gesture-handler';
|
||||
import { HeaderBackButton } from '@react-navigation/stack';
|
||||
|
||||
import StatusBar from '../containers/StatusBar';
|
||||
import RoomHeader from '../containers/RoomHeader';
|
||||
import { withTheme } from '../theme';
|
||||
import SearchHeader from './ThreadMessagesView/SearchHeader';
|
||||
import log, { events, logEvent } from '../utils/log';
|
||||
import database from '../lib/database';
|
||||
import { getUserSelector } from '../selectors/login';
|
||||
import { getHeaderTitlePosition } from '../containers/Header';
|
||||
import * as HeaderButton from '../containers/HeaderButton';
|
||||
import BackgroundContainer from '../containers/BackgroundContainer';
|
||||
import SafeAreaView from '../containers/SafeAreaView';
|
||||
import ActivityIndicator from '../containers/ActivityIndicator';
|
||||
import RoomItem, { ROW_HEIGHT } from '../presentation/RoomItem';
|
||||
import RocketChat from '../lib/rocketchat';
|
||||
import { withDimensions } from '../dimensions';
|
||||
import { isIOS } from '../utils/deviceInfo';
|
||||
import { themes } from '../constants/colors';
|
||||
import debounce from '../utils/debounce';
|
||||
import { showErrorAlert } from '../utils/info';
|
||||
import { goRoom } from '../utils/goRoom';
|
||||
import I18n from '../i18n';
|
||||
|
||||
const API_FETCH_COUNT = 50;
|
||||
|
||||
const getItemLayout = (data, index) => ({
|
||||
length: data.length,
|
||||
offset: ROW_HEIGHT * index,
|
||||
index
|
||||
});
|
||||
const keyExtractor = item => item._id;
|
||||
|
||||
class TeamChannelsView extends React.Component {
|
||||
static propTypes = {
|
||||
route: PropTypes.object,
|
||||
navigation: PropTypes.object,
|
||||
isMasterDetail: PropTypes.bool,
|
||||
insets: PropTypes.object,
|
||||
theme: PropTypes.string,
|
||||
useRealName: PropTypes.bool,
|
||||
width: PropTypes.number,
|
||||
StoreLastMessage: PropTypes.bool
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.teamId = props.route.params?.teamId;
|
||||
this.state = {
|
||||
loading: true,
|
||||
loadingMore: false,
|
||||
data: [],
|
||||
total: -1,
|
||||
isSearching: false,
|
||||
searchText: '',
|
||||
search: []
|
||||
};
|
||||
this.loadTeam();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.load();
|
||||
}
|
||||
|
||||
loadTeam = async() => {
|
||||
const db = database.active;
|
||||
try {
|
||||
const subCollection = db.get('subscriptions');
|
||||
this.teamChannels = await subCollection.query(
|
||||
Q.where('team_id', Q.eq(this.teamId))
|
||||
);
|
||||
this.team = this.teamChannels?.find(channel => channel.teamMain);
|
||||
this.setHeader();
|
||||
|
||||
if (!this.team) {
|
||||
throw new Error();
|
||||
}
|
||||
} catch {
|
||||
const { navigation } = this.props;
|
||||
navigation.pop();
|
||||
showErrorAlert(I18n.t('Team_not_found'));
|
||||
}
|
||||
}
|
||||
|
||||
load = debounce(async() => {
|
||||
const {
|
||||
loadingMore, total, data, search, isSearching, searchText
|
||||
} = this.state;
|
||||
|
||||
const length = isSearching ? search.length : data.length;
|
||||
if (loadingMore || length === total) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({ loadingMore: true });
|
||||
try {
|
||||
const result = await RocketChat.getTeamListRoom({
|
||||
teamId: this.teamId,
|
||||
offset: length,
|
||||
count: API_FETCH_COUNT,
|
||||
type: 'all',
|
||||
filter: searchText
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
const newState = {
|
||||
loading: false,
|
||||
loadingMore: false,
|
||||
total: result.total
|
||||
};
|
||||
const rooms = result.rooms.map((room) => {
|
||||
const record = this.teamChannels?.find(c => c.rid === room._id);
|
||||
return record ?? room;
|
||||
});
|
||||
if (isSearching) {
|
||||
newState.search = [...search, ...rooms];
|
||||
} else {
|
||||
newState.data = [...data, ...rooms];
|
||||
}
|
||||
|
||||
this.setState(newState);
|
||||
} else {
|
||||
this.setState({ loading: false, loadingMore: false });
|
||||
}
|
||||
} catch (e) {
|
||||
log(e);
|
||||
this.setState({ loading: false, loadingMore: false });
|
||||
}
|
||||
}, 300)
|
||||
|
||||
getHeader = () => {
|
||||
const { isSearching } = this.state;
|
||||
const {
|
||||
navigation, isMasterDetail, insets, theme
|
||||
} = this.props;
|
||||
|
||||
const { team } = this;
|
||||
if (!team) {
|
||||
return;
|
||||
}
|
||||
|
||||
const headerTitlePosition = getHeaderTitlePosition({ insets, numIconsRight: 1 });
|
||||
|
||||
if (isSearching) {
|
||||
return {
|
||||
headerTitleAlign: 'left',
|
||||
headerLeft: () => (
|
||||
<HeaderButton.Container left>
|
||||
<HeaderButton.Item
|
||||
iconName='close'
|
||||
onPress={this.onCancelSearchPress}
|
||||
/>
|
||||
</HeaderButton.Container>
|
||||
),
|
||||
headerTitle: () => <SearchHeader onSearchChangeText={this.onSearchChangeText} />,
|
||||
headerTitleContainerStyle: {
|
||||
left: headerTitlePosition.left,
|
||||
right: headerTitlePosition.right
|
||||
},
|
||||
headerRight: () => null
|
||||
};
|
||||
}
|
||||
|
||||
const options = {
|
||||
headerShown: true,
|
||||
headerTitleAlign: 'left',
|
||||
headerTitleContainerStyle: {
|
||||
left: headerTitlePosition.left,
|
||||
right: headerTitlePosition.right
|
||||
},
|
||||
headerTitle: () => (
|
||||
<RoomHeader
|
||||
title={RocketChat.getRoomTitle(team)}
|
||||
subtitle={team.topic}
|
||||
type={team.t}
|
||||
onPress={this.goRoomActionsView}
|
||||
teamMain
|
||||
/>
|
||||
)
|
||||
};
|
||||
|
||||
if (isMasterDetail) {
|
||||
options.headerLeft = () => <HeaderButton.CloseModal navigation={navigation} />;
|
||||
} else {
|
||||
options.headerLeft = () => (
|
||||
<HeaderBackButton
|
||||
labelVisible={false}
|
||||
onPress={() => navigation.pop()}
|
||||
tintColor={themes[theme].headerTintColor}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
options.headerRight = () => (
|
||||
<HeaderButton.Container>
|
||||
<HeaderButton.Item iconName='search' onPress={this.onSearchPress} />
|
||||
</HeaderButton.Container>
|
||||
);
|
||||
return options;
|
||||
}
|
||||
|
||||
setHeader = () => {
|
||||
const { navigation } = this.props;
|
||||
const options = this.getHeader();
|
||||
navigation.setOptions(options);
|
||||
}
|
||||
|
||||
onSearchPress = () => {
|
||||
logEvent(events.TC_SEARCH);
|
||||
this.setState({ isSearching: true }, () => this.setHeader());
|
||||
}
|
||||
|
||||
onSearchChangeText = debounce((searchText) => {
|
||||
this.setState({
|
||||
searchText, search: [], loading: !!searchText, loadingMore: false, total: -1
|
||||
}, () => {
|
||||
if (searchText) {
|
||||
this.load();
|
||||
}
|
||||
});
|
||||
}, 300)
|
||||
|
||||
onCancelSearchPress = () => {
|
||||
logEvent(events.TC_CANCEL_SEARCH);
|
||||
const { isSearching } = this.state;
|
||||
if (!isSearching) {
|
||||
return;
|
||||
}
|
||||
Keyboard.dismiss();
|
||||
this.setState({ isSearching: false, search: [] }, () => {
|
||||
this.setHeader();
|
||||
});
|
||||
};
|
||||
|
||||
goRoomActionsView = (screen) => {
|
||||
logEvent(events.TC_GO_ACTIONS);
|
||||
const { team } = this;
|
||||
const {
|
||||
navigation, isMasterDetail
|
||||
} = this.props;
|
||||
if (isMasterDetail) {
|
||||
navigation.navigate('ModalStackNavigator', {
|
||||
screen: screen ?? 'RoomActionsView',
|
||||
params: {
|
||||
rid: team.rid, t: team.t, room: team, showCloseModal: false
|
||||
}
|
||||
});
|
||||
} else {
|
||||
navigation.navigate('RoomActionsView', {
|
||||
rid: team.rid, t: team.t, room: team
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getRoomTitle = item => RocketChat.getRoomTitle(item)
|
||||
|
||||
getRoomAvatar = item => RocketChat.getRoomAvatar(item)
|
||||
|
||||
onPressItem = debounce(async(item) => {
|
||||
logEvent(events.TC_GO_ROOM);
|
||||
const { navigation, isMasterDetail } = this.props;
|
||||
try {
|
||||
let params = {};
|
||||
if (item.rid) {
|
||||
params = item;
|
||||
} else {
|
||||
const { room } = await RocketChat.getRoomInfo(item._id);
|
||||
params = {
|
||||
rid: item._id, name: RocketChat.getRoomTitle(room), joinCodeRequired: room.joinCodeRequired, t: room.t, teamId: room.teamId
|
||||
};
|
||||
}
|
||||
if (isMasterDetail) {
|
||||
navigation.pop();
|
||||
}
|
||||
goRoom({ item: params, isMasterDetail, navigationMethod: navigation.push });
|
||||
} catch (e) {
|
||||
// do nothing
|
||||
}
|
||||
}, 1000, true);
|
||||
|
||||
renderItem = ({ item }) => {
|
||||
const {
|
||||
StoreLastMessage,
|
||||
useRealName,
|
||||
theme,
|
||||
width
|
||||
} = this.props;
|
||||
return (
|
||||
<RoomItem
|
||||
item={item}
|
||||
theme={theme}
|
||||
type={item.t}
|
||||
showLastMessage={StoreLastMessage}
|
||||
onPress={this.onPressItem}
|
||||
width={width}
|
||||
useRealName={useRealName}
|
||||
getRoomTitle={this.getRoomTitle}
|
||||
getRoomAvatar={this.getRoomAvatar}
|
||||
swipeEnabled={false}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
renderFooter = () => {
|
||||
const { loadingMore } = this.state;
|
||||
const { theme } = this.props;
|
||||
if (loadingMore) {
|
||||
return <ActivityIndicator theme={theme} />;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
renderScroll = () => {
|
||||
const {
|
||||
loading, data, search, isSearching, searchText
|
||||
} = this.state;
|
||||
if (loading) {
|
||||
return <BackgroundContainer loading />;
|
||||
}
|
||||
if (isSearching && !search.length) {
|
||||
return <BackgroundContainer text={searchText ? I18n.t('No_team_channels_found') : ''} />;
|
||||
}
|
||||
if (!isSearching && !data.length) {
|
||||
return <BackgroundContainer text={I18n.t('No_team_channels_found')} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<FlatList
|
||||
data={isSearching ? search : data}
|
||||
extraData={isSearching ? search : data}
|
||||
keyExtractor={keyExtractor}
|
||||
renderItem={this.renderItem}
|
||||
getItemLayout={getItemLayout}
|
||||
removeClippedSubviews={isIOS}
|
||||
keyboardShouldPersistTaps='always'
|
||||
onEndReached={() => this.load()}
|
||||
onEndReachedThreshold={0.5}
|
||||
ListFooterComponent={this.renderFooter}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
console.count(`${ this.constructor.name }.render calls`);
|
||||
return (
|
||||
<SafeAreaView testID='team-channels-view'>
|
||||
<StatusBar />
|
||||
{this.renderScroll()}
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
baseUrl: state.server.server,
|
||||
user: getUserSelector(state),
|
||||
useRealName: state.settings.UI_Use_Real_Name,
|
||||
isMasterDetail: state.app.isMasterDetail,
|
||||
StoreLastMessage: state.settings.Store_Last_Message
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withDimensions(withSafeAreaInsets(withTheme(TeamChannelsView))));
|
|
@ -28,7 +28,7 @@ import * as List from '../../containers/List';
|
|||
import Dropdown from './Dropdown';
|
||||
import DropdownItemHeader from './Dropdown/DropdownItemHeader';
|
||||
import { FILTER } from './filters';
|
||||
import NoDataFound from './NoDataFound';
|
||||
import BackgroundContainer from '../../containers/BackgroundContainer';
|
||||
import { isIOS } from '../../utils/deviceInfo';
|
||||
import { getBadgeColor, makeThreadName } from '../../utils/room';
|
||||
import { getHeaderTitlePosition } from '../../containers/Header';
|
||||
|
@ -463,7 +463,7 @@ class ThreadMessagesView extends React.Component {
|
|||
return (
|
||||
<>
|
||||
{this.renderHeader()}
|
||||
<NoDataFound text={text} />
|
||||
<BackgroundContainer text={text} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ describe('Broadcast room', () => {
|
|||
await element(by.id('create-channel-submit')).tap();
|
||||
await waitFor(element(by.id('room-view'))).toBeVisible().withTimeout(60000);
|
||||
await waitFor(element(by.id(`room-view-title-broadcast${ data.random }`))).toBeVisible().withTimeout(60000);
|
||||
await element(by.id('room-view-header-actions')).tap();
|
||||
await element(by.id('room-header')).tap();
|
||||
await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(5000);
|
||||
await element(by.id('room-actions-info')).tap();
|
||||
await waitFor(element(by.id('room-info-view'))).toBeVisible().withTimeout(2000);
|
||||
|
|
|
@ -15,7 +15,7 @@ async function navigateToRoom() {
|
|||
}
|
||||
|
||||
async function navigateToRoomActions() {
|
||||
await element(by.id('room-view-header-actions')).tap();
|
||||
await element(by.id('room-header')).tap();
|
||||
await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(5000);
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ describe('Join public room', () => {
|
|||
// Render - Header
|
||||
describe('Header', async() => {
|
||||
it('should have actions button ', async() => {
|
||||
await expect(element(by.id('room-view-header-actions'))).toBeVisible();
|
||||
await expect(element(by.id('room-header'))).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ async function navigateToRoom() {
|
|||
}
|
||||
|
||||
async function navigateToRoomActions() {
|
||||
await element(by.id('room-view-header-actions')).tap();
|
||||
await element(by.id('room-header')).tap();
|
||||
await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(5000);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ describe('Room screen', () => {
|
|||
// Render - Header
|
||||
describe('Header', async() => {
|
||||
it('should have actions button ', async() => {
|
||||
await expect(element(by.id('room-view-header-actions'))).toExist();
|
||||
await expect(element(by.id('room-header'))).toExist();
|
||||
});
|
||||
|
||||
it('should have threads button ', async() => {
|
||||
|
|
|
@ -16,7 +16,7 @@ async function navigateToRoomActions(type) {
|
|||
await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toExist().withTimeout(60000);
|
||||
await element(by.id(`rooms-list-view-item-${ room }`)).tap();
|
||||
await waitFor(element(by.id('room-view'))).toExist().withTimeout(2000);
|
||||
await element(by.id('room-view-header-actions')).tap();
|
||||
await element(by.id('room-header')).tap();
|
||||
await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(5000);
|
||||
}
|
||||
|
||||
|
@ -218,7 +218,7 @@ describe('Room actions screen', () => {
|
|||
await starMessage('messageToStar')
|
||||
|
||||
//Back into Room Actions
|
||||
await element(by.id('room-view-header-actions')).tap();
|
||||
await element(by.id('room-header')).tap();
|
||||
await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(5000);
|
||||
|
||||
//Go to starred messages
|
||||
|
@ -246,7 +246,7 @@ describe('Room actions screen', () => {
|
|||
await pinMessage('messageToPin')
|
||||
|
||||
//Back into Room Actions
|
||||
await element(by.id('room-view-header-actions')).tap();
|
||||
await element(by.id('room-header')).tap();
|
||||
await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(5000);
|
||||
await element(by.type('UIScrollView')).atIndex(1).scrollTo('bottom');
|
||||
await waitFor(element(by.id('room-actions-pinned'))).toExist();
|
||||
|
@ -270,7 +270,7 @@ describe('Room actions screen', () => {
|
|||
await mockMessage('messageToFind');
|
||||
|
||||
//Back into Room Actions
|
||||
await element(by.id('room-view-header-actions')).tap();
|
||||
await element(by.id('room-header')).tap();
|
||||
await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(5000);
|
||||
|
||||
await element(by.id('room-actions-search')).tap();
|
||||
|
@ -499,7 +499,7 @@ describe('Room actions screen', () => {
|
|||
});
|
||||
|
||||
it('should navigate to direct message', async() => {
|
||||
await element(by.id('room-view-header-actions')).tap();
|
||||
await element(by.id('room-header')).tap();
|
||||
await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(5000);
|
||||
await element(by.id('room-actions-members')).tap();
|
||||
await waitFor(element(by.id('room-members-view'))).toExist().withTimeout(2000);
|
||||
|
|
|
@ -74,8 +74,8 @@ describe('Discussion', () => {
|
|||
|
||||
describe('Check RoomActionsView render', async() => {
|
||||
it('should navigete to RoomActionsView', async() => {
|
||||
await waitFor(element(by.id('room-view-header-actions'))).toBeVisible().withTimeout(5000);
|
||||
await element(by.id('room-view-header-actions')).tap();
|
||||
await waitFor(element(by.id('room-header'))).toBeVisible().withTimeout(5000);
|
||||
await element(by.id('room-header')).tap();
|
||||
await waitFor(element(by.id('room-actions-view'))).toBeVisible().withTimeout(5000);
|
||||
});
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ describe('Threads', () => {
|
|||
// Render - Header
|
||||
describe('Header', async() => {
|
||||
it('should have actions button ', async() => {
|
||||
await expect(element(by.id('room-view-header-actions'))).toExist();
|
||||
await expect(element(by.id('room-header'))).toExist();
|
||||
});
|
||||
|
||||
it('should have threads button ', async() => {
|
||||
|
@ -105,8 +105,8 @@ describe('Threads', () => {
|
|||
const messageText = 'threadonly';
|
||||
await mockMessage(messageText);
|
||||
await tapBack();
|
||||
await waitFor(element(by.id('room-view-header-actions').and(by.label(`${ mainRoom }`)))).toBeVisible().withTimeout(2000);
|
||||
await waitFor(element(by.id('room-view-header-actions').and(by.label(`${ data.random }thread`)))).toBeNotVisible().withTimeout(2000);
|
||||
await waitFor(element(by.id('room-header').and(by.label(`${ mainRoom }`)))).toBeVisible().withTimeout(2000);
|
||||
await waitFor(element(by.id('room-header').and(by.label(`${ data.random }thread`)))).toBeNotVisible().withTimeout(2000);
|
||||
await sleep(500) //TODO: Find a better way to wait for the animation to finish and the messagebox-input to be available and usable :(
|
||||
await waitFor(element(by.label(`${ data.random }${ messageText }`)).atIndex(0)).toNotExist().withTimeout(2000);
|
||||
});
|
||||
|
@ -118,8 +118,8 @@ describe('Threads', () => {
|
|||
await element(by.id('messagebox-send-to-channel')).tap();
|
||||
await element(by.id('messagebox-send-message')).tap();
|
||||
await tapBack();
|
||||
await waitFor(element(by.id('room-view-header-actions').and(by.label(`${ mainRoom }`)))).toBeVisible().withTimeout(2000);
|
||||
await waitFor(element(by.id('room-view-header-actions').and(by.label(`${ data.random }thread`)))).toBeNotVisible().withTimeout(2000);
|
||||
await waitFor(element(by.id('room-header').and(by.label(`${ mainRoom }`)))).toBeVisible().withTimeout(2000);
|
||||
await waitFor(element(by.id('room-header').and(by.label(`${ data.random }thread`)))).toBeNotVisible().withTimeout(2000);
|
||||
await sleep(500) //TODO: Find a better way to wait for the animation to finish and the messagebox-input to be available and usable :(
|
||||
await waitFor(element(by.label(messageText)).atIndex(0)).toExist().withTimeout(2000);
|
||||
});
|
||||
|
@ -133,8 +133,8 @@ describe('Threads', () => {
|
|||
await element(by.id('messagebox-send-to-channel')).tap();
|
||||
await element(by.id('messagebox-send-message')).tap();
|
||||
await tapBack();
|
||||
await waitFor(element(by.id('room-view-header-actions').and(by.label(`${ mainRoom }`)))).toBeVisible().withTimeout(2000);
|
||||
await waitFor(element(by.id('room-view-header-actions').and(by.label(`${ data.random }thread`)))).toBeNotVisible().withTimeout(2000);
|
||||
await waitFor(element(by.id('room-header').and(by.label(`${ mainRoom }`)))).toBeVisible().withTimeout(2000);
|
||||
await waitFor(element(by.id('room-header').and(by.label(`${ data.random }thread`)))).toBeNotVisible().withTimeout(2000);
|
||||
await sleep(500) //TODO: Find a better way to wait for the animation to finish and the messagebox-input to be available and usable :(
|
||||
|
||||
await element(by.id(`message-thread-replied-on-${ thread }`)).tap();
|
||||
|
|
|
@ -17,7 +17,7 @@ async function navigateToRoomInfo(type) {
|
|||
await waitFor(element(by.id(`rooms-list-view-item-${ room }`))).toExist().withTimeout(60000);
|
||||
await element(by.id(`rooms-list-view-item-${ room }`)).tap();
|
||||
await waitFor(element(by.id('room-view'))).toExist().withTimeout(2000);
|
||||
await element(by.id('room-view-header-actions')).tap();
|
||||
await element(by.id('room-header')).tap();
|
||||
await waitFor(element(by.id('room-actions-view'))).toExist().withTimeout(5000);
|
||||
await element(by.id('room-actions-info')).tap();
|
||||
await waitFor(element(by.id('room-info-view'))).toExist().withTimeout(2000);
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
import React from 'react';
|
||||
import { ScrollView, View, StyleSheet } from 'react-native';
|
||||
import { HeaderBackButton } from '@react-navigation/stack';
|
||||
|
||||
import HeaderComponent from '../../app/views/RoomView/Header/Header';
|
||||
// import { CustomHeaderButtons, Item } from '../../app/containers/HeaderButton';
|
||||
import StoriesSeparator from './StoriesSeparator';
|
||||
import { isIOS } from '../../app/utils/deviceInfo';
|
||||
import { themes } from '../../app/constants/colors';
|
||||
|
||||
let _theme = 'light';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
height: isIOS ? 44 : 56,
|
||||
borderTopWidth: 1,
|
||||
borderBottomWidth: 1,
|
||||
marginVertical: 6
|
||||
}
|
||||
});
|
||||
|
||||
const Header = props => (
|
||||
<View style={[styles.container, { backgroundColor: themes[_theme].headerBackground }]}>
|
||||
<HeaderBackButton />
|
||||
<HeaderComponent
|
||||
title='test'
|
||||
type='d'
|
||||
width={375}
|
||||
height={480}
|
||||
theme={_theme}
|
||||
{...props}
|
||||
/>
|
||||
{/* not working because we use withTheme */}
|
||||
{/* <CustomHeaderButtons>
|
||||
<Item title='thread' iconName='thread' />
|
||||
</CustomHeaderButtons>
|
||||
<CustomHeaderButtons>
|
||||
<Item title='more' iconName='menu' />
|
||||
</CustomHeaderButtons> */}
|
||||
</View>
|
||||
);
|
||||
|
||||
// eslint-disable-next-line react/prop-types
|
||||
export default ({ theme }) => {
|
||||
_theme = theme;
|
||||
return (
|
||||
<ScrollView style={{ backgroundColor: themes[theme].auxiliaryBackground }}>
|
||||
<StoriesSeparator title='Basic' theme={theme} />
|
||||
<Header />
|
||||
|
||||
<StoriesSeparator title='Types' theme={theme} />
|
||||
<Header type='d' />
|
||||
<Header type='c' />
|
||||
<Header type='p' />
|
||||
<Header type='discussion' />
|
||||
<Header type='thread' />
|
||||
|
||||
<StoriesSeparator title='Typing' theme={theme} />
|
||||
<Header usersTyping={['diego.mello']} />
|
||||
<Header usersTyping={['diego.mello', 'rocket.cat']} />
|
||||
<Header usersTyping={['diego.mello', 'rocket.cat', 'detoxrn']} />
|
||||
|
||||
<StoriesSeparator title='Title scroll' theme={theme} />
|
||||
<Header title='Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.' />
|
||||
<Header
|
||||
title='Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'
|
||||
usersTyping={['diego.mello', 'rocket.cat', 'detoxrn']}
|
||||
/>
|
||||
</ScrollView>
|
||||
);
|
||||
};
|
|
@ -14,6 +14,8 @@ import Markdown from './Markdown';
|
|||
import './HeaderButtons';
|
||||
import './UnreadBadge';
|
||||
import '../../app/views/ThreadMessagesView/Item.stories.js';
|
||||
import '../../app/containers/BackgroundContainer/index.stories.js';
|
||||
import '../../app/containers/RoomHeader/RoomHeader.stories.js';
|
||||
import Avatar from './Avatar';
|
||||
// import RoomViewHeader from './RoomViewHeader';
|
||||
|
||||
|
|
Loading…
Reference in New Issue