parent
6b4100d517
commit
f74b8e685d
11 changed files with 256 additions and 78 deletions
|
|
@ -4,16 +4,21 @@
|
|||
import React, {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
Animated,
|
||||
Platform,
|
||||
TouchableHighlight,
|
||||
Text,
|
||||
View
|
||||
} from 'react-native';
|
||||
import {intlShape} from 'react-intl';
|
||||
|
||||
import Badge from 'app/components/badge';
|
||||
import ChannelIcon from 'app/components/channel_icon';
|
||||
import {wrapWithPreventDoubleTap} from 'app/utils/tap';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
|
||||
const {View: AnimatedView} = Animated;
|
||||
|
||||
export default class ChannelItem extends PureComponent {
|
||||
static propTypes = {
|
||||
channelId: PropTypes.string.isRequired,
|
||||
|
|
@ -22,12 +27,17 @@ export default class ChannelItem extends PureComponent {
|
|||
fake: PropTypes.bool,
|
||||
isUnread: PropTypes.bool,
|
||||
mentions: PropTypes.number.isRequired,
|
||||
navigator: PropTypes.object,
|
||||
onSelectChannel: PropTypes.func.isRequired,
|
||||
status: PropTypes.string,
|
||||
type: PropTypes.string.isRequired,
|
||||
theme: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
intl: intlShape
|
||||
};
|
||||
|
||||
onPress = wrapWithPreventDoubleTap(() => {
|
||||
const {channelId, currentChannelId, displayName, fake, onSelectChannel, type} = this.props;
|
||||
requestAnimationFrame(() => {
|
||||
|
|
@ -35,6 +45,30 @@ export default class ChannelItem extends PureComponent {
|
|||
});
|
||||
});
|
||||
|
||||
onPreview = () => {
|
||||
const {channelId, navigator} = this.props;
|
||||
if (Platform.OS === 'ios' && navigator && this.previewRef) {
|
||||
const {intl} = this.context;
|
||||
|
||||
navigator.push({
|
||||
screen: 'ChannelPeek',
|
||||
previewCommit: false,
|
||||
previewView: this.previewRef,
|
||||
previewActions: [{
|
||||
id: 'action-mark-as-read',
|
||||
title: intl.formatMessage({id: 'mobile.channel.markAsRead', defaultMessage: 'Mark As Read'})
|
||||
}],
|
||||
passProps: {
|
||||
channelId
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
setPreviewRef = (ref) => {
|
||||
this.previewRef = ref;
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
channelId,
|
||||
|
|
@ -93,25 +127,28 @@ export default class ChannelItem extends PureComponent {
|
|||
);
|
||||
|
||||
return (
|
||||
<TouchableHighlight
|
||||
underlayColor={changeOpacity(theme.sidebarTextHoverBg, 0.5)}
|
||||
onPress={this.onPress}
|
||||
>
|
||||
<View style={style.container}>
|
||||
{extraBorder}
|
||||
<View style={[style.item, extraItemStyle]}>
|
||||
{icon}
|
||||
<Text
|
||||
style={[style.text, extraTextStyle]}
|
||||
ellipsizeMode='tail'
|
||||
numberOfLines={1}
|
||||
>
|
||||
{displayName}
|
||||
</Text>
|
||||
{badge}
|
||||
<AnimatedView ref={this.setPreviewRef}>
|
||||
<TouchableHighlight
|
||||
underlayColor={changeOpacity(theme.sidebarTextHoverBg, 0.5)}
|
||||
onPress={this.onPress}
|
||||
onLongPress={this.onPreview}
|
||||
>
|
||||
<View style={style.container}>
|
||||
{extraBorder}
|
||||
<View style={[style.item, extraItemStyle]}>
|
||||
{icon}
|
||||
<Text
|
||||
style={[style.text, extraTextStyle]}
|
||||
ellipsizeMode='tail'
|
||||
numberOfLines={1}
|
||||
>
|
||||
{displayName}
|
||||
</Text>
|
||||
{badge}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
</TouchableHighlight>
|
||||
</AnimatedView>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {
|
|||
TouchableHighlight,
|
||||
View
|
||||
} from 'react-native';
|
||||
import {injectIntl, intlShape} from 'react-intl';
|
||||
import {intlShape} from 'react-intl';
|
||||
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
|
||||
|
||||
import {General} from 'mattermost-redux/constants';
|
||||
|
|
@ -21,12 +21,11 @@ import UnreadIndicator from 'app/components/channel_drawer/channels_list/unread_
|
|||
import {wrapWithPreventDoubleTap} from 'app/utils/tap';
|
||||
import {changeOpacity} from 'app/utils/theme';
|
||||
|
||||
class List extends PureComponent {
|
||||
export default class List extends PureComponent {
|
||||
static propTypes = {
|
||||
canCreatePrivateChannels: PropTypes.bool.isRequired,
|
||||
directChannelIds: PropTypes.array.isRequired,
|
||||
favoriteChannelIds: PropTypes.array.isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
navigator: PropTypes.object,
|
||||
onSelectChannel: PropTypes.func.isRequired,
|
||||
publicChannelIds: PropTypes.array.isRequired,
|
||||
|
|
@ -36,6 +35,10 @@ class List extends PureComponent {
|
|||
unreadChannelIds: PropTypes.array.isRequired
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
intl: intlShape
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
|
|
@ -140,7 +143,8 @@ class List extends PureComponent {
|
|||
};
|
||||
|
||||
goToCreatePrivateChannel = wrapWithPreventDoubleTap(() => {
|
||||
const {intl, navigator, theme} = this.props;
|
||||
const {navigator, theme} = this.props;
|
||||
const {intl} = this.context;
|
||||
|
||||
navigator.showModal({
|
||||
screen: 'CreateChannel',
|
||||
|
|
@ -162,7 +166,8 @@ class List extends PureComponent {
|
|||
});
|
||||
|
||||
goToDirectMessages = wrapWithPreventDoubleTap(() => {
|
||||
const {intl, navigator, theme} = this.props;
|
||||
const {navigator, theme} = this.props;
|
||||
const {intl} = this.context;
|
||||
|
||||
navigator.showModal({
|
||||
screen: 'MoreDirectMessages',
|
||||
|
|
@ -186,7 +191,8 @@ class List extends PureComponent {
|
|||
});
|
||||
|
||||
goToMoreChannels = wrapWithPreventDoubleTap(() => {
|
||||
const {intl, navigator, theme} = this.props;
|
||||
const {navigator, theme} = this.props;
|
||||
const {intl} = this.context;
|
||||
|
||||
navigator.showModal({
|
||||
screen: 'MoreChannels',
|
||||
|
|
@ -245,6 +251,7 @@ class List extends PureComponent {
|
|||
return (
|
||||
<ChannelItem
|
||||
channelId={item}
|
||||
navigator={this.props.navigator}
|
||||
onSelectChannel={this.onSelectChannel}
|
||||
/>
|
||||
);
|
||||
|
|
@ -255,13 +262,15 @@ class List extends PureComponent {
|
|||
<ChannelItem
|
||||
channelId={item}
|
||||
isUnread={true}
|
||||
navigator={this.props.navigator}
|
||||
onSelectChannel={this.onSelectChannel}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
renderSectionHeader = ({section}) => {
|
||||
const {intl, styles} = this.props;
|
||||
const {styles} = this.props;
|
||||
const {intl} = this.context;
|
||||
const {
|
||||
action,
|
||||
bottomSeparator,
|
||||
|
|
@ -346,5 +355,3 @@ class List extends PureComponent {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default injectIntl(List);
|
||||
|
|
|
|||
|
|
@ -3,40 +3,45 @@
|
|||
|
||||
import {connect} from 'react-redux';
|
||||
import {General, RequestStatus} from 'mattermost-redux/constants';
|
||||
import {getCurrentChannel} from 'mattermost-redux/selectors/entities/channels';
|
||||
import {getCurrentUser, getProfilesInCurrentChannel} from 'mattermost-redux/selectors/entities/users';
|
||||
import {makeGetChannel} from 'mattermost-redux/selectors/entities/channels';
|
||||
import {getCurrentUser, makeGetProfilesInChannel} from 'mattermost-redux/selectors/entities/users';
|
||||
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
|
||||
import ChannelIntro from './channel_intro';
|
||||
|
||||
function mapStateToProps(state) {
|
||||
const currentChannel = getCurrentChannel(state) || {};
|
||||
const currentUser = getCurrentUser(state) || {};
|
||||
const {status: getPostsRequestStatus} = state.requests.posts.getPosts;
|
||||
function makeMapStateToProps() {
|
||||
const getChannel = makeGetChannel();
|
||||
const getProfilesInChannel = makeGetProfilesInChannel();
|
||||
|
||||
let currentChannelMembers = [];
|
||||
if (currentChannel.type === General.DM_CHANNEL) {
|
||||
const otherChannelMember = currentChannel.name.split('__').find((m) => m !== currentUser.id);
|
||||
const otherProfile = state.entities.users.profiles[otherChannelMember];
|
||||
if (otherProfile) {
|
||||
currentChannelMembers.push(otherProfile);
|
||||
return function mapStateToProps(state, ownProps) {
|
||||
const currentChannel = getChannel(state, {id: ownProps.channelId}) || {};
|
||||
const currentUser = getCurrentUser(state) || {};
|
||||
const {status: getPostsRequestStatus} = state.requests.posts.getPosts;
|
||||
|
||||
let currentChannelMembers = [];
|
||||
if (currentChannel.type === General.DM_CHANNEL) {
|
||||
const otherChannelMember = currentChannel.name.split('__').find((m) => m !== currentUser.id);
|
||||
const otherProfile = state.entities.users.profiles[otherChannelMember];
|
||||
if (otherProfile) {
|
||||
currentChannelMembers.push(otherProfile);
|
||||
}
|
||||
} else {
|
||||
currentChannelMembers = getProfilesInChannel(state, ownProps.channelId) || [];
|
||||
currentChannelMembers = currentChannelMembers.filter((m) => m.id !== currentUser.id);
|
||||
}
|
||||
} else {
|
||||
currentChannelMembers = getProfilesInCurrentChannel(state) || [];
|
||||
currentChannelMembers = currentChannelMembers.filter((m) => m.id !== currentUser.id);
|
||||
}
|
||||
|
||||
const creator = currentChannel.creator_id === currentUser.id ? currentUser : state.entities.users.profiles[currentChannel.creator_id];
|
||||
const postsInChannel = state.entities.posts.postsInChannel[currentChannel.id] || [];
|
||||
const creator = currentChannel.creator_id === currentUser.id ? currentUser : state.entities.users.profiles[currentChannel.creator_id];
|
||||
const postsInChannel = state.entities.posts.postsInChannel[ownProps.channelId] || [];
|
||||
|
||||
return {
|
||||
creator,
|
||||
currentChannel,
|
||||
currentChannelMembers,
|
||||
isLoadingPosts: !postsInChannel.length && getPostsRequestStatus === RequestStatus.STARTED,
|
||||
theme: getTheme(state)
|
||||
return {
|
||||
creator,
|
||||
currentChannel,
|
||||
currentChannelMembers,
|
||||
isLoadingPosts: !postsInChannel.length && getPostsRequestStatus === RequestStatus.STARTED,
|
||||
theme: getTheme(state)
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(ChannelIntro);
|
||||
export default connect(makeMapStateToProps)(ChannelIntro);
|
||||
|
|
|
|||
|
|
@ -207,7 +207,12 @@ export default class PostList extends PureComponent {
|
|||
);
|
||||
}
|
||||
|
||||
return <ChannelIntro navigator={this.props.navigator}/>;
|
||||
return (
|
||||
<ChannelIntro
|
||||
channelId={this.props.channelId}
|
||||
navigator={this.props.navigator}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
|
|
|
|||
102
app/screens/channel_peek/channel_peek.js
Normal file
102
app/screens/channel_peek/channel_peek.js
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import React, {PureComponent} from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {View} from 'react-native';
|
||||
|
||||
import PostList from 'app/components/post_list';
|
||||
import {makeStyleSheetFromTheme} from 'app/utils/theme';
|
||||
|
||||
export default class ChannelPeek extends PureComponent {
|
||||
static propTypes = {
|
||||
actions: PropTypes.shape({
|
||||
loadPostsIfNecessaryWithRetry: PropTypes.func.isRequired,
|
||||
markChannelAsRead: PropTypes.func.isRequired
|
||||
}).isRequired,
|
||||
channelId: PropTypes.string.isRequired,
|
||||
currentUserId: PropTypes.string,
|
||||
lastViewedAt: PropTypes.number,
|
||||
navigator: PropTypes.object,
|
||||
postIds: PropTypes.array.isRequired,
|
||||
theme: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
postVisibility: 15
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent);
|
||||
props.actions.loadPostsIfNecessaryWithRetry(props.channelId);
|
||||
this.state = {
|
||||
visiblePostIds: this.getVisiblePostIds(props)
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const {postIds: nextPostIds} = nextProps;
|
||||
|
||||
let visiblePostIds = this.state.visiblePostIds;
|
||||
|
||||
if (nextPostIds !== this.props.postIds) {
|
||||
visiblePostIds = this.getVisiblePostIds(nextProps);
|
||||
}
|
||||
|
||||
this.setState({
|
||||
visiblePostIds
|
||||
});
|
||||
}
|
||||
|
||||
getVisiblePostIds = (props) => {
|
||||
return props.postIds.slice(0, 15);
|
||||
};
|
||||
|
||||
onNavigatorEvent = (event) => {
|
||||
if (event.type === 'PreviewActionPress') {
|
||||
if (event.id === 'action-mark-as-read') {
|
||||
const {actions, channelId} = this.props;
|
||||
actions.markChannelAsRead(channelId);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
channelId,
|
||||
currentUserId,
|
||||
lastViewedAt,
|
||||
navigator,
|
||||
theme
|
||||
} = this.props;
|
||||
|
||||
const {visiblePostIds} = this.state;
|
||||
const style = getStyle(theme);
|
||||
|
||||
return (
|
||||
<View style={style.container}>
|
||||
<PostList
|
||||
postIds={visiblePostIds}
|
||||
showLoadMore={false}
|
||||
renderReplies={true}
|
||||
indicateNewMessages={true}
|
||||
currentUserId={currentUserId}
|
||||
lastViewedAt={lastViewedAt}
|
||||
channelId={channelId}
|
||||
navigator={navigator}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const getStyle = makeStyleSheetFromTheme((theme) => {
|
||||
return {
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: theme.centerChannelBg
|
||||
}
|
||||
};
|
||||
});
|
||||
37
app/screens/channel_peek/index.js
Normal file
37
app/screens/channel_peek/index.js
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {connect} from 'react-redux';
|
||||
|
||||
import {markChannelAsRead} from 'mattermost-redux/actions/channels';
|
||||
import {getPostIdsInChannel} from 'mattermost-redux/selectors/entities/posts';
|
||||
import {getMyChannelMember} from 'mattermost-redux/selectors/entities/channels';
|
||||
import {getCurrentUserId} from 'mattermost-redux/selectors/entities/users';
|
||||
import {loadPostsIfNecessaryWithRetry} from 'app/actions/views/channel';
|
||||
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
|
||||
|
||||
import ChannelPeek from './channel_peek';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
const channelId = ownProps.channelId;
|
||||
|
||||
return {
|
||||
channelId,
|
||||
currentUserId: getCurrentUserId(state),
|
||||
postIds: getPostIdsInChannel(state, channelId),
|
||||
lastViewedAt: getMyChannelMember(state, channelId).last_viewed_at,
|
||||
theme: getTheme(state)
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
loadPostsIfNecessaryWithRetry,
|
||||
markChannelAsRead
|
||||
}, dispatch)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ChannelPeek);
|
||||
|
|
@ -12,6 +12,7 @@ import Channel from 'app/screens/channel';
|
|||
import ChannelAddMembers from 'app/screens/channel_add_members';
|
||||
import ChannelInfo from 'app/screens/channel_info';
|
||||
import ChannelMembers from 'app/screens/channel_members';
|
||||
import ChannelPeek from 'app/screens/channel_peek';
|
||||
import ClientUpgrade from 'app/screens/client_upgrade';
|
||||
import Code from 'app/screens/code';
|
||||
import CreateChannel from 'app/screens/create_channel';
|
||||
|
|
@ -63,6 +64,7 @@ export function registerScreens(store, Provider) {
|
|||
Navigation.registerComponent('ChannelAddMembers', () => wrapWithContextProvider(ChannelAddMembers), store, Provider);
|
||||
Navigation.registerComponent('ChannelInfo', () => wrapWithContextProvider(ChannelInfo), store, Provider);
|
||||
Navigation.registerComponent('ChannelMembers', () => wrapWithContextProvider(ChannelMembers), store, Provider);
|
||||
Navigation.registerComponent('ChannelPeek', () => wrapWithContextProvider(ChannelPeek), store, Provider);
|
||||
Navigation.registerComponent('ClientUpgrade', () => wrapWithContextProvider(ClientUpgrade), store, Provider);
|
||||
Navigation.registerComponent('Code', () => wrapWithContextProvider(Code), store, Provider);
|
||||
Navigation.registerComponent('CreateChannel', () => wrapWithContextProvider(CreateChannel), store, Provider);
|
||||
|
|
|
|||
|
|
@ -1908,6 +1908,7 @@
|
|||
"mobile.android.photos_permission_denied_title": "Photo library access is required",
|
||||
"mobile.android.videos_permission_denied_description": "To upload videos from your library, please change your permission settings.",
|
||||
"mobile.android.videos_permission_denied_title": "Video library access is required",
|
||||
"mobile.channel.markAsRead": "Mark As Read",
|
||||
"mobile.channel_drawer.search": "Jump to...",
|
||||
"mobile.channel_info.alertMessageDeleteChannel": "Are you sure you want to delete the {term} {name}?",
|
||||
"mobile.channel_info.alertMessageLeaveChannel": "Are you sure you want to leave the {term} {name}?",
|
||||
|
|
|
|||
|
|
@ -9,4 +9,4 @@ SPEC CHECKSUMS:
|
|||
|
||||
PODFILE CHECKSUM: 100c8053d4d12b6c3889d716c02d8b6e1840ed7c
|
||||
|
||||
COCOAPODS: 1.3.0
|
||||
COCOAPODS: 1.3.1
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
"react-native-keyboard-aware-scroll-view": "0.4.1",
|
||||
"react-native-linear-gradient": "2.3.0",
|
||||
"react-native-local-auth": "enahum/react-native-local-auth.git",
|
||||
"react-native-navigation": "1.1.260",
|
||||
"react-native-navigation": "1.1.295",
|
||||
"react-native-notifications": "enahum/react-native-notifications.git",
|
||||
"react-native-orientation": "enahum/react-native-orientation.git",
|
||||
"react-native-passcode-status": "1.1.0",
|
||||
|
|
|
|||
28
yarn.lock
28
yarn.lock
|
|
@ -3959,27 +3959,9 @@ makeerror@1.0.x:
|
|||
dependencies:
|
||||
tmpl "1.0.x"
|
||||
|
||||
"mattermost-redux@file:../mattermost-redux":
|
||||
mattermost-redux@mattermost/mattermost-redux#master:
|
||||
version "1.0.1"
|
||||
dependencies:
|
||||
deep-equal "1.0.1"
|
||||
form-data "2.3.1"
|
||||
harmony-reflect "1.5.1"
|
||||
isomorphic-fetch "2.2.1"
|
||||
mime-db "1.30.0"
|
||||
redux "3.7.2"
|
||||
redux-action-buffer "1.1.0"
|
||||
redux-batched-actions "0.2.0"
|
||||
redux-offline "git+https://github.com/enahum/redux-offline.git"
|
||||
redux-persist "4.9.1"
|
||||
redux-thunk "2.2.0"
|
||||
reselect "3.0.1"
|
||||
serialize-error "2.1.0"
|
||||
shallow-equals "1.0.0"
|
||||
|
||||
mattermost-redux@mattermost/mattermost-redux:
|
||||
version "1.0.1"
|
||||
resolved "https://codeload.github.com/mattermost/mattermost-redux/tar.gz/c293dff26e4db3cde91bf405677700c9fc6a58d8"
|
||||
resolved "https://codeload.github.com/mattermost/mattermost-redux/tar.gz/4f36c293b136cdfb9f44b9536a5006084d0dc758"
|
||||
dependencies:
|
||||
deep-equal "1.0.1"
|
||||
form-data "2.3.1"
|
||||
|
|
@ -5137,9 +5119,9 @@ react-native-mock@0.3.1:
|
|||
react-timer-mixin "^0.13.3"
|
||||
warning "^2.1.0"
|
||||
|
||||
react-native-navigation@1.1.260:
|
||||
version "1.1.260"
|
||||
resolved "https://registry.yarnpkg.com/react-native-navigation/-/react-native-navigation-1.1.260.tgz#b886e23ab302f330145ecba94029807920421f97"
|
||||
react-native-navigation@1.1.295:
|
||||
version "1.1.295"
|
||||
resolved "https://registry.yarnpkg.com/react-native-navigation/-/react-native-navigation-1.1.295.tgz#3ee6b2fc4f94671246498ed285f3592355c063d3"
|
||||
dependencies:
|
||||
lodash "4.x.x"
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue