MM-44663/tappable-channel-names (#6997)
* ADD: channel name tappable in post with channel name fields * touchable feedback added to the channel name * rippple effect added in toucable * Text color of channel name changes as its presses * ui colors and borderRadius fixed in channelinfo * comments resolved: dependency added, function name changed * comment resolved: condition added onChannelNamePressed
This commit is contained in:
parent
07aa748cd7
commit
66c7a70e49
3 changed files with 94 additions and 25 deletions
|
|
@ -1,11 +1,14 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import React, {useCallback, useMemo, useState} from 'react';
|
||||
import {View, Text, StyleSheet} from 'react-native';
|
||||
|
||||
import {switchToChannelById} from '@actions/remote/channel';
|
||||
import TouchableWithFeedback from '@app/components/touchable_with_feedback';
|
||||
import {useServerUrl} from '@app/context/server';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {typography} from '@utils/typography';
|
||||
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
|
|
@ -15,51 +18,88 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
|||
container: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginVertical: 8,
|
||||
paddingHorizontal: 16,
|
||||
paddingHorizontal: 8,
|
||||
},
|
||||
channelContainer: {
|
||||
borderRadius: 4,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
channel: {
|
||||
...typography('Body', 75, 'SemiBold'),
|
||||
color: theme.centerChannelColor,
|
||||
marginRight: 5,
|
||||
color: changeOpacity(theme.centerChannelColor, 0.72),
|
||||
flexShrink: 1,
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 4,
|
||||
},
|
||||
teamContainer: {
|
||||
borderColor: theme.centerChannelColor,
|
||||
borderLeftWidth: StyleSheet.hairlineWidth,
|
||||
flexShrink: 1,
|
||||
},
|
||||
team: {
|
||||
...typography('Body', 75, 'Light'),
|
||||
color: theme.centerChannelColor,
|
||||
marginLeft: 5,
|
||||
...typography('Body', 75, 'Regular'),
|
||||
color: changeOpacity(theme.centerChannelColor, 0.72),
|
||||
marginLeft: 8,
|
||||
},
|
||||
}));
|
||||
|
||||
type Props = {
|
||||
channelId: ChannelModel['id'];
|
||||
channelName: ChannelModel['displayName'];
|
||||
teamName: TeamModel['displayName'];
|
||||
testID?: string;
|
||||
}
|
||||
|
||||
function ChannelInfo({channelName, teamName, testID}: Props) {
|
||||
function ChannelInfo({channelId, channelName, teamName, testID}: Props) {
|
||||
const theme = useTheme();
|
||||
const styles = getStyleSheet(theme);
|
||||
const serverUrl = useServerUrl();
|
||||
|
||||
const [isPressed, setIsPressed] = useState<Boolean>(false);
|
||||
|
||||
const channelNameStyle = useMemo(() => (
|
||||
[styles.channel, isPressed ? {color: theme.buttonBg} : null]
|
||||
), [isPressed, styles, theme]);
|
||||
|
||||
const teamContainerStyle = useMemo(() => (
|
||||
[styles.teamContainer, isPressed ? null : {borderLeftWidth: StyleSheet.hairlineWidth}]
|
||||
), [isPressed, styles]);
|
||||
|
||||
const onChannelNamePressed = useCallback(() => {
|
||||
if (channelId) {
|
||||
switchToChannelById(serverUrl, channelId);
|
||||
}
|
||||
}, [serverUrl, channelId]);
|
||||
|
||||
const togglePressed = useCallback(() => {
|
||||
setIsPressed((prevState) => !prevState);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View
|
||||
style={styles.container}
|
||||
testID={testID}
|
||||
>
|
||||
<Text
|
||||
style={styles.channel}
|
||||
testID='channel_display_name'
|
||||
numberOfLines={1}
|
||||
>
|
||||
{channelName}
|
||||
</Text>
|
||||
<View style={styles.channelContainer}>
|
||||
<TouchableWithFeedback
|
||||
onPress={onChannelNamePressed}
|
||||
type={'native'}
|
||||
underlayColor={changeOpacity(theme.buttonBg, 0.08)}
|
||||
onPressIn={togglePressed}
|
||||
onPressOut={togglePressed}
|
||||
>
|
||||
<Text
|
||||
style={channelNameStyle}
|
||||
testID='channel_display_name'
|
||||
numberOfLines={1}
|
||||
>
|
||||
{channelName}
|
||||
</Text>
|
||||
</TouchableWithFeedback>
|
||||
</View>
|
||||
{Boolean(teamName) && (
|
||||
<View style={styles.teamContainer}>
|
||||
<View style={teamContainerStyle}>
|
||||
<Text
|
||||
style={styles.team}
|
||||
testID='team_display_name'
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ const enhance = withObservables(['post'], ({post, database}: {post: PostModel} &
|
|||
const channel = observeChannel(database, post.channelId);
|
||||
|
||||
return {
|
||||
channelId: channel.pipe(
|
||||
switchMap((chan) => (chan ? of$(chan.id) : '')),
|
||||
),
|
||||
channelName: channel.pipe(
|
||||
switchMap((chan) => (chan ? of$(chan.displayName) : '')),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useCallback} from 'react';
|
||||
import React, {useCallback, useMemo, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {Text, TouchableHighlight, View} from 'react-native';
|
||||
|
||||
import {switchToChannelById} from '@actions/remote/channel';
|
||||
import {fetchAndSwitchToThread} from '@actions/remote/thread';
|
||||
import TouchableWithFeedback from '@app/components/touchable_with_feedback';
|
||||
import FormattedText from '@components/formatted_text';
|
||||
import FriendlyDate from '@components/friendly_date';
|
||||
import RemoveMarkdown from '@components/remove_markdown';
|
||||
|
|
@ -129,10 +131,26 @@ const Thread = ({author, channel, location, post, teammateNameDisplay, testID, t
|
|||
const textStyles = getMarkdownTextStyles(theme);
|
||||
const serverUrl = useServerUrl();
|
||||
|
||||
const [isChannelNamePressed, setIsChannelNamePressed] = useState<Boolean>(false);
|
||||
|
||||
const channelNameStyle = useMemo(() => (
|
||||
[styles.channelName, isChannelNamePressed ? {color: theme.buttonBg} : null]
|
||||
), [isChannelNamePressed, styles, theme]);
|
||||
|
||||
const togglePressed = useCallback(() => {
|
||||
setIsChannelNamePressed((prevState) => !prevState);
|
||||
}, []);
|
||||
|
||||
const showThread = useCallback(preventDoubleTap(() => {
|
||||
fetchAndSwitchToThread(serverUrl, thread.id);
|
||||
}), [serverUrl, thread.id]);
|
||||
|
||||
const onChannelNamePressed = useCallback(() => {
|
||||
if (channel?.id) {
|
||||
switchToChannelById(serverUrl, channel?.id);
|
||||
}
|
||||
}, [serverUrl, channel?.id]);
|
||||
|
||||
const showThreadOptions = useCallback(() => {
|
||||
const passProps = {thread};
|
||||
const title = isTablet ? intl.formatMessage({id: 'thread.options.title', defaultMessage: 'Thread Actions'}) : '';
|
||||
|
|
@ -229,13 +247,21 @@ const Thread = ({author, channel, location, post, teammateNameDisplay, testID, t
|
|||
{name}
|
||||
{threadStarterName !== channel?.displayName && (
|
||||
<View style={styles.channelNameContainer}>
|
||||
<Text
|
||||
style={styles.channelName}
|
||||
numberOfLines={1}
|
||||
testID={`${threadItemTestId}.thread_starter.channel_display_name`}
|
||||
<TouchableWithFeedback
|
||||
onPress={onChannelNamePressed}
|
||||
type={'native'}
|
||||
underlayColor={changeOpacity(theme.buttonBg, 0.08)}
|
||||
onPressIn={togglePressed}
|
||||
onPressOut={togglePressed}
|
||||
>
|
||||
{channel?.displayName}
|
||||
</Text>
|
||||
<Text
|
||||
style={channelNameStyle}
|
||||
numberOfLines={1}
|
||||
testID={`${threadItemTestId}.thread_starter.channel_display_name`}
|
||||
>
|
||||
{channel?.displayName}
|
||||
</Text>
|
||||
</TouchableWithFeedback>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
|
|
|||
Loading…
Reference in a new issue