forked from Ivasoft/mattermost-mobile
* Remove mattermost-redux * Move mm-redux files into app/redux * Add @redux path to tsconfig.json * Fix imports * Install missing dependencies * Fix tsc errors * Fix i18n_utils test * Fix more imports * Remove redux websocket * Fix tests * Rename @redux * Apply changes from mattermost-redux PR 1103 * Remove mattermost-redux mention in template * Add missing imports * Rename app/redux/ to app/mm-redux/ * Remove test file * Fix fetching Sidebar GM profiles Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
203 lines
5.7 KiB
JavaScript
203 lines
5.7 KiB
JavaScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
import React, {PureComponent} from 'react';
|
|
import PropTypes from 'prop-types';
|
|
import {
|
|
Animated,
|
|
Easing,
|
|
View,
|
|
Dimensions,
|
|
} from 'react-native';
|
|
import {ImageContent} from 'rn-placeholder';
|
|
|
|
import EventEmitter from '@mm-redux/utils/event_emitter';
|
|
|
|
import CustomPropTypes from 'app/constants/custom_prop_types';
|
|
import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme';
|
|
import {paddingHorizontal as padding} from 'app/components/safe_area_view/iphone_x_spacing';
|
|
|
|
const {View: AnimatedView} = Animated;
|
|
|
|
function calculateMaxRows(height) {
|
|
return Math.round(height / 100);
|
|
}
|
|
|
|
export default class ChannelLoader extends PureComponent {
|
|
static propTypes = {
|
|
actions: PropTypes.shape({
|
|
handleSelectChannel: PropTypes.func.isRequired,
|
|
setChannelLoading: PropTypes.func.isRequired,
|
|
}).isRequired,
|
|
backgroundColor: PropTypes.string,
|
|
channelIsLoading: PropTypes.bool.isRequired,
|
|
style: CustomPropTypes.Style,
|
|
theme: PropTypes.object.isRequired,
|
|
height: PropTypes.number,
|
|
isLandscape: PropTypes.bool.isRequired,
|
|
};
|
|
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
const height = props.height || Dimensions.get('window').height;
|
|
const maxRows = calculateMaxRows(height);
|
|
|
|
this.state = {
|
|
barsOpacity: new Animated.Value(0.6),
|
|
switch: false,
|
|
maxRows,
|
|
};
|
|
}
|
|
|
|
static getDerivedStateFromProps(nextProps, prevState) {
|
|
const state = {};
|
|
|
|
if (nextProps.height) {
|
|
state.maxRows = calculateMaxRows(nextProps.height);
|
|
}
|
|
if (!nextProps.channelIsLoading && prevState.switch) {
|
|
state.switch = false;
|
|
state.channel = null;
|
|
}
|
|
|
|
return Object.keys(state) ? state : null;
|
|
}
|
|
|
|
componentDidMount() {
|
|
EventEmitter.on('switch_channel', this.handleChannelSwitch);
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
EventEmitter.off('switch_channel', this.handleChannelSwitch);
|
|
}
|
|
|
|
startLoadingAnimation = () => {
|
|
Animated.loop(
|
|
Animated.sequence([
|
|
Animated.timing(this.state.barsOpacity, {
|
|
toValue: 1,
|
|
duration: 750,
|
|
easing: Easing.quad,
|
|
useNativeDriver: true,
|
|
}),
|
|
Animated.timing(this.state.barsOpacity, {
|
|
toValue: 0.6,
|
|
duration: 750,
|
|
easing: Easing.quad,
|
|
useNativeDriver: true,
|
|
}),
|
|
]),
|
|
).start();
|
|
};
|
|
|
|
stopLoadingAnimation = () => {
|
|
Animated.timing(
|
|
this.state.barsOpacity,
|
|
).stop();
|
|
}
|
|
|
|
componentDidUpdate(prevProps) {
|
|
if (prevProps.channelIsLoading === false && this.props.channelIsLoading === true) {
|
|
this.startLoadingAnimation();
|
|
} else if (prevProps.channelIsLoading === true && this.props.channelIsLoading === false) {
|
|
this.stopLoadingAnimation();
|
|
}
|
|
|
|
if (this.state.switch) {
|
|
const {
|
|
handleSelectChannel,
|
|
setChannelLoading,
|
|
} = this.props.actions;
|
|
|
|
const {channel} = this.state;
|
|
|
|
setTimeout(() => {
|
|
handleSelectChannel(channel.id);
|
|
setChannelLoading(false);
|
|
}, 250);
|
|
}
|
|
}
|
|
|
|
buildSections({key, style, bg, color}) {
|
|
return (
|
|
<AnimatedView
|
|
key={key}
|
|
style={[style.section, {backgroundColor: bg}, {opacity: this.state.barsOpacity}]}
|
|
>
|
|
<ImageContent
|
|
size={32}
|
|
animate='fade'
|
|
lineNumber={3}
|
|
lineSpacing={5}
|
|
firstLineWidth='80%'
|
|
hasRadius={true}
|
|
textSize={14}
|
|
color={changeOpacity(color, 0.15)}
|
|
/>
|
|
</AnimatedView>
|
|
);
|
|
}
|
|
|
|
handleChannelSwitch = (channel, currentChannelId) => {
|
|
if (channel.id === currentChannelId) {
|
|
this.props.actions.setChannelLoading(false);
|
|
} else {
|
|
this.setState({switch: true, channel});
|
|
}
|
|
};
|
|
|
|
handleLayout = (e) => {
|
|
const {height} = e.nativeEvent.layout;
|
|
const maxRows = calculateMaxRows(height);
|
|
this.setState({maxRows});
|
|
}
|
|
|
|
render() {
|
|
const {
|
|
channelIsLoading,
|
|
style: styleProp,
|
|
theme,
|
|
isLandscape,
|
|
} = this.props;
|
|
|
|
if (!channelIsLoading) {
|
|
return null;
|
|
}
|
|
|
|
const style = getStyleSheet(theme);
|
|
const bg = this.props.backgroundColor || theme.centerChannelBg;
|
|
|
|
return (
|
|
<View
|
|
style={[style.container, styleProp, padding(isLandscape), {backgroundColor: bg}]}
|
|
onLayout={this.handleLayout}
|
|
>
|
|
{Array(this.state.maxRows).fill().map((item, index) => this.buildSections({
|
|
key: index,
|
|
style,
|
|
bg,
|
|
color: theme.centerChannelColor,
|
|
}))}
|
|
</View>
|
|
);
|
|
}
|
|
}
|
|
|
|
const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
|
return {
|
|
container: {
|
|
flex: 1,
|
|
overflow: 'hidden',
|
|
},
|
|
section: {
|
|
backgroundColor: theme.centerChannelBg,
|
|
flexDirection: 'row',
|
|
flex: 1,
|
|
paddingLeft: 12,
|
|
paddingRight: 20,
|
|
marginVertical: 10,
|
|
},
|
|
};
|
|
});
|