[GEKIDOU] Bottom Tab Navigation (#5600)
* Started with bottom tabs layout * code clean up * Added animation to bottom tab bar * returns null if not focused * code clean up * Updating layout * Updated modal screen * Updated animation * Updated animation * Fix SafeArea on Home * A few clean ups * code clean up * Fix issue with navigation on Android * Use React Navigation in combination of RNN & create bottom tab bar * Set tab bar line separator height to 0.5 * Fix snapshot tests * Add home tab mention badge * Apply new themes * Home Tab badge * Remove unused constants Co-authored-by: Avinash Lingaloo <> Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
This commit is contained in:
parent
b5c5949b7d
commit
2c193f2133
56 changed files with 4454 additions and 2674 deletions
Binary file not shown.
117
app/components/badge/index.tsx
Normal file
117
app/components/badge/index.tsx
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import * as React from 'react';
|
||||
import {Animated, StyleProp, StyleSheet, TextStyle} from 'react-native';
|
||||
|
||||
import {useTheme} from '@context/theme';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* Whether the badge is visible
|
||||
*/
|
||||
visible: boolean;
|
||||
|
||||
/**
|
||||
* Content of the `Badge`.
|
||||
*/
|
||||
children?: string | number;
|
||||
|
||||
/**
|
||||
* Size of the `Badge`.
|
||||
*/
|
||||
size?: number;
|
||||
|
||||
/**
|
||||
* Style object for the tab bar container.
|
||||
*/
|
||||
style?: Animated.WithAnimatedValue<StyleProp<TextStyle>>;
|
||||
};
|
||||
|
||||
export default function Badge({
|
||||
visible = true,
|
||||
size = 18,
|
||||
children,
|
||||
style,
|
||||
...rest
|
||||
}: Props) {
|
||||
const [opacity] = React.useState(() => new Animated.Value(visible ? 1 : 0));
|
||||
const [rendered, setRendered] = React.useState(Boolean(visible));
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!rendered) {
|
||||
return;
|
||||
}
|
||||
|
||||
Animated.timing(opacity, {
|
||||
toValue: visible ? 1 : 0,
|
||||
duration: 150,
|
||||
useNativeDriver: true,
|
||||
}).start(({finished}) => {
|
||||
if (finished && !visible) {
|
||||
setRendered(false);
|
||||
}
|
||||
});
|
||||
}, [opacity, rendered, visible]);
|
||||
|
||||
if (visible && !rendered) {
|
||||
setRendered(true);
|
||||
}
|
||||
|
||||
if (!visible && !rendered) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// @ts-expect-error: backgroundColor definitely exists
|
||||
const {backgroundColor = theme.buttonBg, ...restStyle} =
|
||||
StyleSheet.flatten(style) || {};
|
||||
const textColor = theme.buttonColor;
|
||||
const borderRadius = size / 2;
|
||||
const fontSize = Math.floor((size * 3) / 4);
|
||||
|
||||
return (
|
||||
<Animated.Text
|
||||
numberOfLines={1}
|
||||
style={[
|
||||
{
|
||||
opacity,
|
||||
transform: [
|
||||
{
|
||||
scale: opacity.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [0.5, 1],
|
||||
}),
|
||||
},
|
||||
],
|
||||
backgroundColor,
|
||||
color: textColor,
|
||||
fontSize,
|
||||
lineHeight: size - 1,
|
||||
height: size,
|
||||
minWidth: size,
|
||||
borderRadius,
|
||||
},
|
||||
styles.container,
|
||||
restStyle,
|
||||
]}
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</Animated.Text>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
position: 'absolute',
|
||||
top: -1,
|
||||
left: 15,
|
||||
alignSelf: 'flex-end',
|
||||
textAlign: 'center',
|
||||
paddingHorizontal: 4,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
});
|
||||
|
|
@ -5,7 +5,7 @@ exports[`ErrorText should match snapshot 1`] = `
|
|||
style={
|
||||
Array [
|
||||
Object {
|
||||
"color": "#fd5960",
|
||||
"color": "#d24b4e",
|
||||
"fontSize": 12,
|
||||
"marginBottom": 15,
|
||||
"marginTop": 15,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ describe('ErrorText', () => {
|
|||
fontSize: 14,
|
||||
marginHorizontal: 15,
|
||||
},
|
||||
theme: Preferences.THEMES.default,
|
||||
theme: Preferences.THEMES.denim,
|
||||
error: 'Username must begin with a letter and contain between 3 and 22 characters including numbers, lowercase letters, and the symbols',
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -13,9 +13,9 @@ import FormattedText from '@components/formatted_text';
|
|||
import ProgressiveImage from '@components/progressive_image';
|
||||
import SlideUpPanelItem, {ITEM_HEIGHT} from '@components/slide_up_panel_item';
|
||||
import TouchableWithFeedback from '@components/touchable_with_feedback';
|
||||
import {Navigation} from '@constants';
|
||||
import {Device, Navigation} from '@constants';
|
||||
import {useServerUrl} from '@context/server_url';
|
||||
import {usePermanentSidebar, useSplitView} from '@hooks/device';
|
||||
import {useSplitView} from '@hooks/device';
|
||||
import {showModalOverCurrentContext} from '@screens/navigation';
|
||||
import {openGallerWithMockFile} from '@utils/gallery';
|
||||
import {generateId} from '@utils/general';
|
||||
|
|
@ -55,7 +55,6 @@ const MarkdownImage = ({
|
|||
const intl = useIntl();
|
||||
const isSplitView = useSplitView();
|
||||
const managedConfig = useManagedConfig();
|
||||
const permanentSidebar = usePermanentSidebar();
|
||||
const genericFileId = useRef(generateId()).current;
|
||||
const metadata = imagesMetadata?.[source] || Object.values(imagesMetadata || {})[0];
|
||||
const [failed, setFailed] = useState(isGifTooLarge(metadata));
|
||||
|
|
@ -87,7 +86,7 @@ const MarkdownImage = ({
|
|||
height: originalSize.height,
|
||||
};
|
||||
|
||||
const {height, width} = calculateDimensions(fileInfo.height, fileInfo.width, getViewPortWidth(isReplyPost, (permanentSidebar && !isSplitView)));
|
||||
const {height, width} = calculateDimensions(fileInfo.height, fileInfo.width, getViewPortWidth(isReplyPost, Device.IS_TABLET && !isSplitView));
|
||||
|
||||
const handleLinkPress = useCallback(() => {
|
||||
if (linkDestination) {
|
||||
|
|
|
|||
133
app/components/profile_picture/index.tsx
Normal file
133
app/components/profile_picture/index.tsx
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useEffect} from 'react';
|
||||
import {Platform, StyleProp, View, ViewProps, ViewStyle} from 'react-native';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
|
||||
// import {fetchStatusInBatch} from '@actions/remote/user';
|
||||
// import UserStatus from '@components/user_status';
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import {useServerUrl} from '@context/server_url';
|
||||
import {useTheme} from '@context/theme';
|
||||
import NetworkManager from '@init/network_manager';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
import type {Client} from '@client/rest';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
|
||||
const STATUS_BUFFER = Platform.select({
|
||||
ios: 3,
|
||||
android: 2,
|
||||
});
|
||||
|
||||
type ProfilePictureProps = {
|
||||
author?: UserModel;
|
||||
iconSize?: number;
|
||||
showStatus?: boolean;
|
||||
size: number;
|
||||
statusSize?: number;
|
||||
statusStyle?: StyleProp<ViewProps>;
|
||||
testID?: string;
|
||||
};
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||
return {
|
||||
container: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderRadius: 80,
|
||||
},
|
||||
icon: {
|
||||
color: changeOpacity(theme.centerChannelColor, 0.48),
|
||||
},
|
||||
statusWrapper: {
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
overflow: 'hidden',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: theme.centerChannelBg,
|
||||
borderWidth: 1,
|
||||
borderColor: theme.centerChannelBg,
|
||||
},
|
||||
status: {
|
||||
color: theme.centerChannelBg,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const ProfilePicture = ({author, iconSize, showStatus = true, size = 64, statusSize = 14, statusStyle, testID}: ProfilePictureProps) => {
|
||||
const theme = useTheme();
|
||||
const serverUrl = useServerUrl();
|
||||
const style = getStyleSheet(theme);
|
||||
const buffer = showStatus ? (STATUS_BUFFER || 0) : 0;
|
||||
let client: Client | undefined;
|
||||
|
||||
try {
|
||||
client = NetworkManager.getClient(serverUrl);
|
||||
} catch {
|
||||
// handle below that the client is not set
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (author && !author.status && showStatus) {
|
||||
// fetchStatusInBatch(serverUrl, author.id);
|
||||
}
|
||||
}, []);
|
||||
|
||||
let statusIcon;
|
||||
let containerStyle: StyleProp<ViewStyle> = {
|
||||
width: size + buffer,
|
||||
height: size + buffer,
|
||||
};
|
||||
|
||||
if (author?.status && !author.isBot && showStatus) {
|
||||
statusIcon = (
|
||||
<View style={[style.statusWrapper, statusStyle, {borderRadius: statusSize / 2}]}>
|
||||
{/* <UserStatus
|
||||
size={statusSize}
|
||||
status={author.status}
|
||||
/> */}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
let image;
|
||||
if (author && client) {
|
||||
const pictureUrl = client.getProfilePictureUrl(author.id, author.lastPictureUpdate);
|
||||
image = (
|
||||
<FastImage
|
||||
key={pictureUrl}
|
||||
style={{width: size, height: size, borderRadius: (size / 2)}}
|
||||
source={{uri: `${serverUrl}${pictureUrl}`}}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
containerStyle = {
|
||||
width: size + (buffer - 1),
|
||||
height: size + (buffer - 1),
|
||||
backgroundColor: changeOpacity(theme.centerChannelColor, 0.08),
|
||||
};
|
||||
image = (
|
||||
<CompassIcon
|
||||
name='account-outline'
|
||||
size={iconSize || size}
|
||||
style={style.icon}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View
|
||||
style={[style.container, containerStyle]}
|
||||
testID={`${testID}.${author?.id}`}
|
||||
>
|
||||
{image}
|
||||
{statusIcon}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProfilePicture;
|
||||
|
|
@ -21,9 +21,7 @@ export default {
|
|||
IMAGES_PATH: `${FileSystem.cacheDirectory}/Images`,
|
||||
IS_IPHONE_WITH_INSETS: Platform.OS === 'ios' && DeviceInfo.hasNotch(),
|
||||
IS_TABLET: DeviceInfo.isTablet(),
|
||||
PERMANENT_SIDEBAR_SETTINGS: 'PERMANENT_SIDEBAR_SETTINGS',
|
||||
PUSH_NOTIFY_ANDROID_REACT_NATIVE: 'android_rn',
|
||||
PUSH_NOTIFY_APPLE_REACT_NATIVE: 'apple_rn',
|
||||
TABLET_WIDTH: 250,
|
||||
VIDEOS_PATH: `${FileSystem.cacheDirectory}/Videos`,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,10 +9,6 @@ const Navigation = keyMirror({
|
|||
NAVIGATION_ERROR_TEAMS: null,
|
||||
NAVIGATION_SHOW_OVERLAY: null,
|
||||
NAVIGATION_DISMISS_AND_POP_TO_ROOT: null,
|
||||
CLOSE_MAIN_SIDEBAR: null,
|
||||
MAIN_SIDEBAR_DID_CLOSE: null,
|
||||
MAIN_SIDEBAR_DID_OPEN: null,
|
||||
CLOSE_SETTINGS_SIDEBAR: null,
|
||||
BLUR_POST_DRAFT: null,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -41,115 +41,142 @@ const Preferences: Record<string, any> = {
|
|||
CATEGORY_THEME: 'theme',
|
||||
TEAMS_ORDER: 'teams_order',
|
||||
THEMES: {
|
||||
default: {
|
||||
type: 'Mattermost',
|
||||
sidebarBg: '#145dbf',
|
||||
denim: {
|
||||
type: 'Denim',
|
||||
sidebarBg: '#1e325c',
|
||||
sidebarText: '#ffffff',
|
||||
sidebarUnreadText: '#ffffff',
|
||||
sidebarTextHoverBg: '#4578bf',
|
||||
sidebarTextHoverBg: '#28427b',
|
||||
sidebarTextActiveBorder: '#579eff',
|
||||
sidebarTextActiveColor: '#ffffff',
|
||||
sidebarHeaderBg: '#1153ab',
|
||||
sidebarTextActiveColor: '#5d89ea',
|
||||
sidebarHeaderBg: '#192a4d',
|
||||
sidebarHeaderTextColor: '#ffffff',
|
||||
onlineIndicator: '#06d6a0',
|
||||
awayIndicator: '#ffbc42',
|
||||
dndIndicator: '#f74343',
|
||||
sidebarTeamBarBg: '#14213e',
|
||||
onlineIndicator: '#3db887',
|
||||
awayIndicator: '#ffbc1f',
|
||||
dndIndicator: '#d24b4e',
|
||||
mentionBg: '#ffffff',
|
||||
mentionBj: '#ffffff',
|
||||
mentionColor: '#145dbf',
|
||||
mentionColor: '#1e325c',
|
||||
centerChannelBg: '#ffffff',
|
||||
centerChannelColor: '#3d3c40',
|
||||
newMessageSeparator: '#ff8800',
|
||||
linkColor: '#2389d7',
|
||||
buttonBg: '#166de0',
|
||||
centerChannelColor: '#3f4350',
|
||||
newMessageSeparator: '#cc8f00',
|
||||
linkColor: '#386fe5',
|
||||
buttonBg: '#1c58d9',
|
||||
buttonColor: '#ffffff',
|
||||
errorTextColor: '#fd5960',
|
||||
mentionHighlightBg: '#ffe577',
|
||||
mentionHighlightLink: '#166de0',
|
||||
errorTextColor: '#d24b4e',
|
||||
mentionHighlightBg: '#ffd470',
|
||||
mentionHighlightLink: '#1b1d22',
|
||||
codeTheme: 'github',
|
||||
} as Theme,
|
||||
organization: {
|
||||
type: 'Organization',
|
||||
sidebarBg: '#2071a7',
|
||||
},
|
||||
sapphire: {
|
||||
type: 'Sapphire',
|
||||
sidebarBg: '#174ab5',
|
||||
sidebarText: '#ffffff',
|
||||
sidebarUnreadText: '#ffffff',
|
||||
sidebarTextHoverBg: '#136197',
|
||||
sidebarTextActiveBorder: '#7ab0d6',
|
||||
sidebarTextHoverBg: '#2a58ba',
|
||||
sidebarTextActiveBorder: '#57b5f0',
|
||||
sidebarTextActiveColor: '#ffffff',
|
||||
sidebarHeaderBg: '#2f81b7',
|
||||
sidebarHeaderBg: '#1542a2',
|
||||
sidebarHeaderTextColor: '#ffffff',
|
||||
onlineIndicator: '#7dbe00',
|
||||
awayIndicator: '#dcbd4e',
|
||||
dndIndicator: '#ff6a6a',
|
||||
mentionBg: '#fbfbfb',
|
||||
mentionBj: '#fbfbfb',
|
||||
mentionColor: '#2071f7',
|
||||
centerChannelBg: '#f2f4f8',
|
||||
centerChannelColor: '#333333',
|
||||
newMessageSeparator: '#ff8800',
|
||||
linkColor: '#2f81b7',
|
||||
buttonBg: '#1dacfc',
|
||||
sidebarTeamBarBg: '#133a91',
|
||||
onlineIndicator: '#3db887',
|
||||
awayIndicator: '#ffbc1f',
|
||||
dndIndicator: '#d24b4e',
|
||||
mentionBg: '#ffffff',
|
||||
mentionColor: '#174ab5',
|
||||
centerChannelBg: '#ffffff',
|
||||
centerChannelColor: '#3f4350',
|
||||
newMessageSeparator: '#15b7b7',
|
||||
linkColor: '#1c58d9',
|
||||
buttonBg: '#1c58d9',
|
||||
buttonColor: '#ffffff',
|
||||
errorTextColor: '#a94442',
|
||||
mentionHighlightBg: '#f3e197',
|
||||
mentionHighlightLink: '#2f81b7',
|
||||
errorTextColor: '#d24b4e',
|
||||
mentionHighlightBg: '#7ff0f0',
|
||||
mentionHighlightLink: '#0d6e6e',
|
||||
codeTheme: 'github',
|
||||
} as Theme,
|
||||
mattermostDark: {
|
||||
type: 'Mattermost Dark',
|
||||
sidebarBg: '#1b2c3e',
|
||||
},
|
||||
quartz: {
|
||||
type: 'Quartz',
|
||||
sidebarBg: '#f4f4f6',
|
||||
sidebarText: '#090a0b',
|
||||
sidebarUnreadText: '#2d3039',
|
||||
sidebarTextHoverBg: '#ebebed',
|
||||
sidebarTextActiveBorder: '#32a4ec',
|
||||
sidebarTextActiveColor: '#2d3039',
|
||||
sidebarHeaderBg: '#e8e9ed',
|
||||
sidebarHeaderTextColor: '#2d3039',
|
||||
sidebarTeamBarBg: '#dddfe4',
|
||||
onlineIndicator: '#3db887',
|
||||
awayIndicator: '#f5ab07',
|
||||
dndIndicator: '#d24b4e',
|
||||
mentionBg: '#1c58d9',
|
||||
mentionColor: '#ffffff',
|
||||
centerChannelBg: '#ffffff',
|
||||
centerChannelColor: '#3f4350',
|
||||
newMessageSeparator: '#15b7b7',
|
||||
linkColor: '#1c58d9',
|
||||
buttonBg: '#1c58d9',
|
||||
buttonColor: '#ffffff',
|
||||
errorTextColor: '#d24b4e',
|
||||
mentionHighlightBg: '#7ff0f0',
|
||||
mentionHighlightLink: '#0d6e6e',
|
||||
codeTheme: 'github',
|
||||
},
|
||||
indigo: {
|
||||
type: 'Indigo',
|
||||
sidebarBg: '#0f1a2e',
|
||||
sidebarText: '#ffffff',
|
||||
sidebarUnreadText: '#ffffff',
|
||||
sidebarTextHoverBg: '#4a5664',
|
||||
sidebarTextActiveBorder: '#66b9a7',
|
||||
sidebarTextHoverBg: '#222c3f',
|
||||
sidebarTextActiveBorder: '#1279ba',
|
||||
sidebarTextActiveColor: '#ffffff',
|
||||
sidebarHeaderBg: '#1b2c3e',
|
||||
sidebarHeaderTextColor: '#ffffff',
|
||||
onlineIndicator: '#65dcc8',
|
||||
awayIndicator: '#c1b966',
|
||||
dndIndicator: '#e81023',
|
||||
mentionBg: '#b74a4a',
|
||||
mentionBj: '#b74a4a',
|
||||
sidebarHeaderBg: '#152231',
|
||||
sidebarHeaderTextColor: '#dddfe4',
|
||||
sidebarTeamBarBg: '#05080f',
|
||||
onlineIndicator: '#3db887',
|
||||
awayIndicator: '#f5ab00',
|
||||
dndIndicator: '#d24b4e',
|
||||
mentionBg: '#1c58d9',
|
||||
mentionColor: '#ffffff',
|
||||
centerChannelBg: '#2f3e4e',
|
||||
centerChannelColor: '#dddddd',
|
||||
newMessageSeparator: '#5de5da',
|
||||
linkColor: '#a4ffeb',
|
||||
buttonBg: '#4cbba4',
|
||||
centerChannelBg: '#0a111f',
|
||||
centerChannelColor: '#dddfe4',
|
||||
newMessageSeparator: '#81a3ef',
|
||||
linkColor: '#5d89ea',
|
||||
buttonBg: '#386fe5',
|
||||
buttonColor: '#ffffff',
|
||||
errorTextColor: '#ff6461',
|
||||
mentionHighlightBg: '#984063',
|
||||
mentionHighlightLink: '#a4ffeb',
|
||||
codeTheme: 'solarized-dark',
|
||||
} as Theme,
|
||||
windows10: {
|
||||
type: 'Windows Dark',
|
||||
sidebarBg: '#171717',
|
||||
errorTextColor: '#d24b4e',
|
||||
mentionHighlightBg: '#133a91',
|
||||
mentionHighlightLink: '#a4f4f4',
|
||||
codeTheme: 'github',
|
||||
},
|
||||
onyx: {
|
||||
type: 'Onyx',
|
||||
sidebarBg: '#121317',
|
||||
sidebarText: '#ffffff',
|
||||
sidebarUnreadText: '#ffffff',
|
||||
sidebarTextHoverBg: '#302e30',
|
||||
sidebarTextActiveBorder: '#196caf',
|
||||
sidebarTextHoverBg: '#25262a',
|
||||
sidebarTextActiveBorder: '#1592e0',
|
||||
sidebarTextActiveColor: '#ffffff',
|
||||
sidebarHeaderBg: '#1f1f1f',
|
||||
sidebarHeaderTextColor: '#ffffff',
|
||||
onlineIndicator: '#399fff',
|
||||
awayIndicator: '#c1b966',
|
||||
dndIndicator: '#e81023',
|
||||
mentionBg: '#0177e7',
|
||||
mentionBj: '#0177e7',
|
||||
sidebarHeaderBg: '#1b1d22',
|
||||
sidebarHeaderTextColor: '#dddfe4',
|
||||
sidebarTeamBarBg: '#000000',
|
||||
onlineIndicator: '#3db887',
|
||||
awayIndicator: '#f5ab00',
|
||||
dndIndicator: '#d24b4e',
|
||||
mentionBg: '#1c58d9',
|
||||
mentionColor: '#ffffff',
|
||||
centerChannelBg: '#1f1f1f',
|
||||
centerChannelColor: '#dddddd',
|
||||
newMessageSeparator: '#cc992d',
|
||||
linkColor: '#0d93ff',
|
||||
buttonBg: '#0177e7',
|
||||
centerChannelBg: '#090a0b',
|
||||
centerChannelColor: '#dddfe4',
|
||||
newMessageSeparator: '#1adbdb',
|
||||
linkColor: '#5d89ea',
|
||||
buttonBg: '#386fe5',
|
||||
buttonColor: '#ffffff',
|
||||
errorTextColor: '#ff6461',
|
||||
mentionHighlightBg: '#784098',
|
||||
mentionHighlightLink: '#a4ffeb',
|
||||
errorTextColor: '#da6c6e',
|
||||
mentionHighlightBg: '#0d6e6e',
|
||||
mentionHighlightLink: '#a4f4f4',
|
||||
codeTheme: 'monokai',
|
||||
} as Theme,
|
||||
},
|
||||
},
|
||||
} as Record<ThemeKey, Theme>,
|
||||
};
|
||||
|
||||
export default Preferences;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@
|
|||
// See LICENSE.txt for license information.
|
||||
|
||||
export const ABOUT = 'About';
|
||||
export const BOTTOM_SHEET = 'BottomSheet';
|
||||
export const CHANNEL = 'Channel';
|
||||
export const FORGOT_PASSWORD = 'ForgotPassword';
|
||||
export const HOME = 'Home';
|
||||
export const LOGIN = 'Login';
|
||||
export const LOGIN_OPTIONS = 'LoginOptions';
|
||||
export const MAIN_SIDEBAR = 'MainSidebar';
|
||||
|
|
@ -15,13 +17,16 @@ export const THREAD = 'Thread';
|
|||
|
||||
export default {
|
||||
ABOUT,
|
||||
BOTTOM_SHEET,
|
||||
CHANNEL,
|
||||
FORGOT_PASSWORD,
|
||||
HOME,
|
||||
LOGIN,
|
||||
LOGIN_OPTIONS,
|
||||
MAIN_SIDEBAR,
|
||||
MFA,
|
||||
SERVER,
|
||||
SETTINGS_SIDEBAR,
|
||||
SSO,
|
||||
THREAD,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -43,6 +43,10 @@ export const MAX_BADGE_RIGHT_POSITION = -13;
|
|||
export const LARGE_BADGE_RIGHT_POSITION = -11;
|
||||
export const SMALL_BADGE_RIGHT_POSITION = -9;
|
||||
|
||||
export const TABLET = {
|
||||
SIDEBAR_WIDTH: 320,
|
||||
};
|
||||
|
||||
const ViewTypes = keyMirror({
|
||||
DATA_CLEANUP: null,
|
||||
SERVER_URL_CHANGED: null,
|
||||
|
|
@ -132,4 +136,5 @@ export default {
|
|||
SidebarSectionTypes,
|
||||
IOS_HORIZONTAL_LANDSCAPE: 44,
|
||||
INDICATOR_BAR_HEIGHT,
|
||||
TABLET,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -28,9 +28,9 @@ const {SERVER: {PREFERENCE, SYSTEM}} = MM_TABLES;
|
|||
|
||||
function getDefaultThemeByAppearance(): Theme {
|
||||
if (Appearance.getColorScheme() === 'dark') {
|
||||
return Preferences.THEMES.windows10;
|
||||
return Preferences.THEMES.onyx;
|
||||
}
|
||||
return Preferences.THEMES.default;
|
||||
return Preferences.THEMES.denim;
|
||||
}
|
||||
|
||||
const ThemeContext = createContext(getDefaultThemeByAppearance());
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ import {MM_TABLES} from '@constants/database';
|
|||
import ServerUrlProvider from '@context/server_url';
|
||||
import ThemeProvider from '@context/theme';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import Servers from '@database/models/app/servers';
|
||||
|
||||
import type ServersModel from '@typings/database/models/app/servers';
|
||||
|
||||
type State = {
|
||||
database: Database;
|
||||
|
|
@ -25,7 +26,7 @@ export function withServerDatabase<T>(
|
|||
const [state, setState] = useState<State|undefined>();
|
||||
const db = DatabaseManager.appDatabase?.database;
|
||||
|
||||
const observer = async (servers: Servers[]) => {
|
||||
const observer = (servers: ServersModel[]) => {
|
||||
const server = servers.reduce((a, b) => (b.lastActiveAt > a.lastActiveAt ? b : a));
|
||||
|
||||
const serverDatabase = DatabaseManager.serverDatabases[server?.url]?.database;
|
||||
|
|
|
|||
|
|
@ -57,6 +57,9 @@ export default class ChannelModel extends Model {
|
|||
/** A CHANNEL can contain multiple POST (relationship is 1:N) */
|
||||
[POST]: {type: 'has_many', foreignKey: 'channel_id'},
|
||||
|
||||
/** A CHANNEL can contain multiple POST (relationship is 1:N) */
|
||||
[MY_CHANNEL]: {type: 'has_many', foreignKey: 'channel_id'},
|
||||
|
||||
/** A TEAM can be associated to CHANNEL (relationship is 1:N) */
|
||||
[TEAM]: {type: 'belongs_to', key: 'team_id'},
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import {Relation} from '@nozbe/watermelondb';
|
||||
import {field, immutableRelation} from '@nozbe/watermelondb/decorators';
|
||||
import Model from '@nozbe/watermelondb/Model';
|
||||
import Model, {Associations} from '@nozbe/watermelondb/Model';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
|
||||
|
|
@ -18,6 +18,10 @@ export default class MyChannelModel extends Model {
|
|||
/** table (name) : MyChannel */
|
||||
static table = MY_CHANNEL;
|
||||
|
||||
static associations: Associations = {
|
||||
[CHANNEL]: {type: 'belongs_to', key: 'id'},
|
||||
};
|
||||
|
||||
/** last_post_at : The timestamp for any last post on this channel */
|
||||
@field('last_post_at') lastPostAt!: number;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,47 +2,13 @@
|
|||
// See LICENSE.txt for license information.
|
||||
|
||||
import {useEffect, useState} from 'react';
|
||||
import {DeviceEventEmitter, NativeModules, useWindowDimensions} from 'react-native';
|
||||
import {NativeModules, useWindowDimensions} from 'react-native';
|
||||
|
||||
import {Device} from '@constants';
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import DatabaseManager from '@database/manager';
|
||||
|
||||
import type GlobalModel from '@typings/database/models/app/global';
|
||||
|
||||
const {MattermostManaged} = NativeModules;
|
||||
const isRunningInSplitView = MattermostManaged.isRunningInSplitView;
|
||||
|
||||
export function usePermanentSidebar() {
|
||||
const [permanentSidebar, setPermanentSidebar] = useState(Device.IS_TABLET);
|
||||
|
||||
useEffect(() => {
|
||||
const handlePermanentSidebar = async () => {
|
||||
if (Device.IS_TABLET) {
|
||||
const database = DatabaseManager.appDatabase?.database;
|
||||
if (database) {
|
||||
try {
|
||||
const enabled = await database.get(MM_TABLES.APP.GLOBAL).find(Device.PERMANENT_SIDEBAR_SETTINGS) as GlobalModel;
|
||||
setPermanentSidebar(enabled.value === 'true');
|
||||
} catch {
|
||||
setPermanentSidebar(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handlePermanentSidebar();
|
||||
|
||||
const listener = DeviceEventEmitter.addListener(Device.PERMANENT_SIDEBAR_SETTINGS, handlePermanentSidebar);
|
||||
|
||||
return () => {
|
||||
listener.remove();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return permanentSidebar;
|
||||
}
|
||||
|
||||
export function useSplitView() {
|
||||
const [isSplitView, setIsSplitView] = useState(false);
|
||||
const dimensions = useWindowDimensions();
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import AsyncStorage from '@react-native-community/async-storage';
|
||||
import {Device} from 'app/constants';
|
||||
|
||||
if (Device.IS_TABLET) {
|
||||
// TODO: Use the default database to set this property
|
||||
|
||||
AsyncStorage.getItem(Device.PERMANENT_SIDEBAR_SETTINGS).then((value) => {
|
||||
if (!value) {
|
||||
AsyncStorage.setItem(Device.PERMANENT_SIDEBAR_SETTINGS, 'true');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Linking} from 'react-native';
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {useSafeAreaInsets} from 'react-native-safe-area-context';
|
|||
import {useTheme} from '@context/theme';
|
||||
import {Device, View as ViewConstants} from '@constants';
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import {useSplitView} from '@hooks/device';
|
||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
import ChannelTitle from './channel_title';
|
||||
|
|
@ -25,12 +26,14 @@ type ChannelNavBar = {
|
|||
const ChannelNavBar = ({channel, onPress}: ChannelNavBar) => {
|
||||
const insets = useSafeAreaInsets();
|
||||
const theme = useTheme();
|
||||
const isSplitView = useSplitView();
|
||||
const style = getStyleFromTheme(theme);
|
||||
|
||||
const dimensions = useWindowDimensions();
|
||||
const isLandscape = dimensions.width > dimensions.height;
|
||||
|
||||
let height = 0;
|
||||
let paddingTop = 0;
|
||||
let canHaveSubtitle = true;
|
||||
|
||||
const onLayout = ({nativeEvent}: LayoutChangeEvent) => {
|
||||
|
|
@ -64,10 +67,15 @@ const ChannelNavBar = ({channel, onPress}: ChannelNavBar) => {
|
|||
break;
|
||||
}
|
||||
|
||||
if (!Device.IS_TABLET || (Device.IS_TABLET && isSplitView)) {
|
||||
height += insets.top;
|
||||
paddingTop = insets.top;
|
||||
}
|
||||
|
||||
return (
|
||||
<View
|
||||
onLayout={onLayout}
|
||||
style={[style.header, {height: height + insets.top, paddingTop: insets.top, paddingLeft: insets.left, paddingRight: insets.right}]}
|
||||
style={[style.header, {height, paddingTop, paddingLeft: insets.left, paddingRight: insets.right}]}
|
||||
>
|
||||
<ChannelTitle
|
||||
channel={channel}
|
||||
|
|
|
|||
48
app/screens/channel_list/index.tsx
Normal file
48
app/screens/channel_list/index.tsx
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {Text, View} from 'react-native';
|
||||
|
||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
type ChannelProps = {
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
const ChannelList = ({theme}: ChannelProps) => {
|
||||
const styles = getStyleSheet(theme);
|
||||
|
||||
return (
|
||||
<View
|
||||
testID='channel.screen'
|
||||
style={styles.container}
|
||||
>
|
||||
<Text style={styles.screenTitle}>{' Channel Screen '}</Text>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme(() => ({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#ffffff',
|
||||
},
|
||||
tabContainer: {
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
backgroundColor: '#ffffff',
|
||||
},
|
||||
textContainer: {
|
||||
marginTop: 30,
|
||||
alignItems: 'center',
|
||||
},
|
||||
screenTitle: {
|
||||
fontSize: 30,
|
||||
alignSelf: 'center',
|
||||
},
|
||||
}));
|
||||
|
||||
export default ChannelList;
|
||||
|
|
@ -46,7 +46,7 @@ exports[`ForgotPassword should match snapshot 1`] = `
|
|||
style={
|
||||
Array [
|
||||
Object {
|
||||
"color": "#fd5960",
|
||||
"color": "#d24b4e",
|
||||
"fontSize": 12,
|
||||
"marginBottom": 15,
|
||||
"marginTop": 15,
|
||||
|
|
@ -66,7 +66,7 @@ exports[`ForgotPassword should match snapshot 1`] = `
|
|||
style={
|
||||
Array [
|
||||
Object {
|
||||
"color": "rgba(61,60,64,0.6)",
|
||||
"color": "rgba(63,67,80,0.6)",
|
||||
"fontSize": 16,
|
||||
"fontWeight": "300",
|
||||
"lineHeight": 22,
|
||||
|
|
@ -90,7 +90,7 @@ exports[`ForgotPassword should match snapshot 1`] = `
|
|||
keyboardType="email-address"
|
||||
onChangeText={[Function]}
|
||||
placeholder="Email"
|
||||
placeholderTextColor="rgba(61,60,64,0.5)"
|
||||
placeholderTextColor="rgba(63,67,80,0.5)"
|
||||
rejectResponderTermination={true}
|
||||
style={
|
||||
Object {
|
||||
|
|
@ -98,7 +98,7 @@ exports[`ForgotPassword should match snapshot 1`] = `
|
|||
"borderColor": "gainsboro",
|
||||
"borderRadius": 3,
|
||||
"borderWidth": 1,
|
||||
"color": "#3d3c40",
|
||||
"color": "#3f4350",
|
||||
"fontSize": 16,
|
||||
"height": 45,
|
||||
"marginBottom": 5,
|
||||
|
|
@ -124,7 +124,7 @@ exports[`ForgotPassword should match snapshot 1`] = `
|
|||
Object {
|
||||
"alignItems": "center",
|
||||
"alignSelf": "stretch",
|
||||
"borderColor": "#166de0",
|
||||
"borderColor": "#1c58d9",
|
||||
"borderRadius": 3,
|
||||
"borderWidth": 1,
|
||||
"marginTop": 10,
|
||||
|
|
@ -137,7 +137,7 @@ exports[`ForgotPassword should match snapshot 1`] = `
|
|||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "#166de0",
|
||||
"color": "#1c58d9",
|
||||
"fontSize": 17,
|
||||
"textAlign": "center",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ describe('ForgotPassword', () => {
|
|||
const baseProps = {
|
||||
componentId: 'ForgotPassword',
|
||||
serverUrl: 'https://community.mattermost.com',
|
||||
theme: Preferences.THEMES.default,
|
||||
theme: Preferences.THEMES.denim,
|
||||
};
|
||||
|
||||
test('should match snapshot', () => {
|
||||
|
|
|
|||
31
app/screens/home/account/index.tsx
Normal file
31
app/screens/home/account/index.tsx
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {useRoute} from '@react-navigation/native';
|
||||
import React from 'react';
|
||||
import {Text} from 'react-native';
|
||||
import Animated, {AnimatedLayout, FadeInLeft, FadeInRight} from 'react-native-reanimated';
|
||||
import {SafeAreaView} from 'react-native-safe-area-context';
|
||||
|
||||
const AccountScreen = () => {
|
||||
const route = useRoute();
|
||||
const params = route.params! as {direction: string};
|
||||
const entering = params.direction === 'left' ? FadeInLeft : FadeInRight;
|
||||
|
||||
return (
|
||||
<SafeAreaView
|
||||
style={{flex: 1, backgroundColor: 'green'}}
|
||||
>
|
||||
<AnimatedLayout style={{flex: 1}}>
|
||||
<Animated.View
|
||||
entering={entering.duration(150)}
|
||||
style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}
|
||||
>
|
||||
<Text style={{fontSize: 20, color: '#fff'}}>{'Account Screen'}</Text>
|
||||
</Animated.View>
|
||||
</AnimatedLayout>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
export default AccountScreen;
|
||||
97
app/screens/home/channel_list/index.tsx
Normal file
97
app/screens/home/channel_list/index.tsx
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {useIsFocused, useRoute} from '@react-navigation/native';
|
||||
import React from 'react';
|
||||
import {Text, View} from 'react-native';
|
||||
import Animated, {useAnimatedStyle, withTiming} from 'react-native-reanimated';
|
||||
import {SafeAreaView} from 'react-native-safe-area-context';
|
||||
|
||||
import {Device, View as ViewConstants} from '@constants';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {useSplitView} from '@hooks/device';
|
||||
import Channel from '@screens/channel';
|
||||
import {goToScreen} from '@screens/navigation';
|
||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
import type {LaunchProps} from '@typings/launch';
|
||||
|
||||
type ChannelProps = LaunchProps & {
|
||||
time?: number;
|
||||
};
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||
flex: {
|
||||
flex: 1,
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
},
|
||||
sectionContainer: {
|
||||
marginTop: 32,
|
||||
paddingHorizontal: 24,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 24,
|
||||
fontWeight: '600',
|
||||
color: theme.centerChannelColor,
|
||||
},
|
||||
}));
|
||||
|
||||
const ChannelListScreen = (props: ChannelProps) => {
|
||||
const theme = useTheme();
|
||||
const styles = getStyleSheet(theme);
|
||||
const isSplitView = useSplitView();
|
||||
const showTabletLayout = Device.IS_TABLET && !isSplitView;
|
||||
const route = useRoute();
|
||||
const isFocused = useIsFocused();
|
||||
const params = route.params as {direction: string};
|
||||
|
||||
let tabletSidebarStyle;
|
||||
if (showTabletLayout) {
|
||||
const {TABLET} = ViewConstants;
|
||||
tabletSidebarStyle = {maxWidth: TABLET.SIDEBAR_WIDTH};
|
||||
}
|
||||
|
||||
const animated = useAnimatedStyle(() => {
|
||||
if (!isFocused) {
|
||||
let initial = 0;
|
||||
if (params?.direction) {
|
||||
initial = -25;
|
||||
}
|
||||
return {
|
||||
opacity: withTiming(0, {duration: 150}),
|
||||
transform: [{translateX: withTiming(initial, {duration: 150})}],
|
||||
};
|
||||
}
|
||||
return {
|
||||
opacity: withTiming(1, {duration: 150}),
|
||||
transform: [{translateX: withTiming(0, {duration: 150})}],
|
||||
};
|
||||
}, [isFocused, params]);
|
||||
|
||||
return (
|
||||
<SafeAreaView
|
||||
style={styles.flex}
|
||||
>
|
||||
<Animated.View
|
||||
style={[styles.content, animated]}
|
||||
>
|
||||
<View style={[styles.flex, {alignItems: 'center', justifyContent: 'center'}, tabletSidebarStyle]}>
|
||||
<Text
|
||||
onPress={() => goToScreen('Channel', '', undefined, {topBar: {visible: false}})}
|
||||
style={{fontSize: 20, color: '#fff'}}
|
||||
>
|
||||
{'Channel List'}
|
||||
</Text>
|
||||
</View>
|
||||
{showTabletLayout &&
|
||||
<Channel {...props}/>
|
||||
}
|
||||
</Animated.View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChannelListScreen;
|
||||
78
app/screens/home/index.tsx
Normal file
78
app/screens/home/index.tsx
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {NavigationContainer} from '@react-navigation/native';
|
||||
import {createBottomTabNavigator, BottomTabBarProps} from '@react-navigation/bottom-tabs';
|
||||
import React from 'react';
|
||||
import {Platform} from 'react-native';
|
||||
import {enableScreens} from 'react-native-screens';
|
||||
|
||||
import {useTheme} from '@context/theme';
|
||||
|
||||
import Account from './account';
|
||||
import ChannelList from './channel_list';
|
||||
import RecentMentions from './recent_mentions';
|
||||
import Search from './search';
|
||||
import TabBar from './tab_bar';
|
||||
|
||||
import type {LaunchProps} from '@typings/launch';
|
||||
|
||||
if (Platform.OS === 'ios') {
|
||||
// We do this on iOS to avoid conflicts betwen ReactNavigation & Wix ReactNativeNavigation
|
||||
enableScreens(false);
|
||||
}
|
||||
|
||||
type HomeProps = LaunchProps & {
|
||||
time?: number;
|
||||
};
|
||||
|
||||
const Tab = createBottomTabNavigator();
|
||||
|
||||
export default function HomeScreen(props: HomeProps) {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<NavigationContainer
|
||||
theme={{
|
||||
dark: false,
|
||||
colors: {
|
||||
primary: theme.centerChannelColor,
|
||||
background: theme.centerChannelBg,
|
||||
card: theme.centerChannelBg,
|
||||
text: theme.centerChannelColor,
|
||||
border: 'white',
|
||||
notification: theme.mentionHighlightBg,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Tab.Navigator
|
||||
screenOptions={{headerShown: false, lazy: true, unmountOnBlur: true}}
|
||||
tabBar={(tabProps: BottomTabBarProps) => (
|
||||
<TabBar
|
||||
{...tabProps}
|
||||
theme={theme}
|
||||
/>)}
|
||||
>
|
||||
<Tab.Screen
|
||||
name='Home'
|
||||
options={{title: 'Channel', unmountOnBlur: false}}
|
||||
>
|
||||
{() => <ChannelList {...props}/>}
|
||||
</Tab.Screen>
|
||||
<Tab.Screen
|
||||
name='Search'
|
||||
component={Search}
|
||||
options={{unmountOnBlur: false}}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name='Mentions'
|
||||
component={RecentMentions}
|
||||
/>
|
||||
<Tab.Screen
|
||||
name='Account'
|
||||
component={Account}
|
||||
/>
|
||||
</Tab.Navigator>
|
||||
</NavigationContainer>
|
||||
);
|
||||
}
|
||||
31
app/screens/home/recent_mentions/index.tsx
Normal file
31
app/screens/home/recent_mentions/index.tsx
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {useRoute} from '@react-navigation/native';
|
||||
import React from 'react';
|
||||
import {Text} from 'react-native';
|
||||
import Animated, {AnimatedLayout, FadeInLeft, FadeInRight} from 'react-native-reanimated';
|
||||
import {SafeAreaView} from 'react-native-safe-area-context';
|
||||
|
||||
const RecentMentionsScreen = () => {
|
||||
const route = useRoute();
|
||||
const params = route.params! as {direction: string};
|
||||
const entering = params.direction === 'left' ? FadeInLeft : FadeInRight;
|
||||
|
||||
return (
|
||||
<SafeAreaView
|
||||
style={{flex: 1, backgroundColor: 'brown'}}
|
||||
>
|
||||
<AnimatedLayout style={{flex: 1}}>
|
||||
<Animated.View
|
||||
entering={entering.duration(150)}
|
||||
style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}
|
||||
>
|
||||
<Text style={{fontSize: 20, color: '#fff'}}>{'Recent Mentions Screen'}</Text>
|
||||
</Animated.View>
|
||||
</AnimatedLayout>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
export default RecentMentionsScreen;
|
||||
45
app/screens/home/search/index.tsx
Normal file
45
app/screens/home/search/index.tsx
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {useIsFocused, useNavigation} from '@react-navigation/native';
|
||||
import React from 'react';
|
||||
import {Text} from 'react-native';
|
||||
import Animated, {useAnimatedStyle, withTiming} from 'react-native-reanimated';
|
||||
import {SafeAreaView} from 'react-native-safe-area-context';
|
||||
|
||||
const SearchScreen = () => {
|
||||
const nav = useNavigation();
|
||||
const isFocused = useIsFocused();
|
||||
const searchScreenIndex = 1;
|
||||
const stateIndex = nav.getState().index;
|
||||
|
||||
const animated = useAnimatedStyle(() => {
|
||||
if (isFocused) {
|
||||
return {
|
||||
opacity: withTiming(1, {duration: 150}),
|
||||
transform: [{translateX: withTiming(0, {duration: 150})}],
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
opacity: withTiming(0, {duration: 150}),
|
||||
transform: [{translateX: withTiming(stateIndex < searchScreenIndex ? 25 : -25, {duration: 150})}],
|
||||
};
|
||||
}, [isFocused, stateIndex]);
|
||||
|
||||
return (
|
||||
<SafeAreaView
|
||||
style={{flex: 1, backgroundColor: 'blue'}}
|
||||
>
|
||||
<Animated.View
|
||||
style={[{flex: 1, justifyContent: 'center', alignItems: 'center'}, animated]}
|
||||
>
|
||||
{isFocused &&
|
||||
<Text style={{fontSize: 20, color: '#fff'}}>{'Search Screen'}</Text>
|
||||
}
|
||||
</Animated.View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
export default SearchScreen;
|
||||
54
app/screens/home/tab_bar/account.tsx
Normal file
54
app/screens/home/tab_bar/account.tsx
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import React from 'react';
|
||||
import {View} from 'react-native';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import ProfilePicture from '@components/profile_picture';
|
||||
import {MM_TABLES, SYSTEM_IDENTIFIERS} from '@app/constants/database';
|
||||
import {makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
import type SystemModel from '@typings/database/models/servers/system';
|
||||
import type UserModel from '@typings/database/models/servers/user';
|
||||
|
||||
type Props = {
|
||||
currentUser: UserModel;
|
||||
isFocused: boolean;
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
const {SERVER: {SYSTEM, USER}} = MM_TABLES;
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||
selected: {
|
||||
borderWidth: 2,
|
||||
borderColor: theme.buttonBg,
|
||||
borderRadius: 20,
|
||||
},
|
||||
}));
|
||||
|
||||
const Account = ({currentUser, isFocused, theme}: Props) => {
|
||||
const style = getStyleSheet(theme);
|
||||
|
||||
return (
|
||||
<View style={isFocused ? style.selected : undefined}>
|
||||
<ProfilePicture
|
||||
author={currentUser}
|
||||
showStatus={false}
|
||||
size={28}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const withCurrentUser = withObservables([], ({database}: WithDatabaseArgs) => ({
|
||||
currentUser: database.get(SYSTEM).findAndObserve(SYSTEM_IDENTIFIERS.CURRENT_USER_ID).pipe(
|
||||
switchMap((id: SystemModel) => database.get(USER).findAndObserve(id.value)),
|
||||
),
|
||||
}));
|
||||
|
||||
export default withDatabase(withCurrentUser(Account));
|
||||
162
app/screens/home/tab_bar/home.tsx
Normal file
162
app/screens/home/tab_bar/home.tsx
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Q} from '@nozbe/watermelondb';
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import {Platform, View} from 'react-native';
|
||||
|
||||
import {MM_TABLES} from '@constants/database';
|
||||
import Badge from '@components/badge';
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
import type {Subscription} from 'rxjs';
|
||||
|
||||
import type ServersModel from '@typings/database/models/app/servers';
|
||||
import type MyChannelModel from '@typings/database/models/servers/my_channel';
|
||||
|
||||
type Props = {
|
||||
isFocused: boolean;
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
type UnreadMessages = {
|
||||
mentions: number;
|
||||
messages: number;
|
||||
};
|
||||
|
||||
type UnreadSubscription = UnreadMessages & {
|
||||
subscription?: Subscription;
|
||||
}
|
||||
|
||||
const {SERVERS} = MM_TABLES.APP;
|
||||
const {CHANNEL, MY_CHANNEL} = MM_TABLES.SERVER;
|
||||
const subscriptions: Map<string, UnreadSubscription> = new Map();
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||
unread: {
|
||||
left: 16,
|
||||
top: 1,
|
||||
borderColor: theme.centerChannelBg,
|
||||
borderWidth: 2,
|
||||
paddingHorizontal: 0,
|
||||
},
|
||||
mentions: {
|
||||
fontSize: 10,
|
||||
fontWeight: 'bold',
|
||||
fontFamily: 'Open Sans',
|
||||
lineHeight: Platform.select({android: 15, ios: 12.6}),
|
||||
borderColor: theme.centerChannelBg,
|
||||
borderWidth: 2,
|
||||
minWidth: 18,
|
||||
height: 16,
|
||||
},
|
||||
}));
|
||||
|
||||
const Home = ({isFocused, theme}: Props) => {
|
||||
const db = DatabaseManager.appDatabase?.database;
|
||||
const [total, setTotal] = useState<UnreadMessages>({mentions: 0, messages: 0});
|
||||
const style = getStyleSheet(theme);
|
||||
|
||||
const updateTotal = () => {
|
||||
let messages = 0;
|
||||
let mentions = 0;
|
||||
subscriptions.forEach((value) => {
|
||||
messages += value.messages;
|
||||
mentions += value.mentions;
|
||||
});
|
||||
setTotal({mentions, messages});
|
||||
};
|
||||
|
||||
const unreadsSubscription = (serverUrl: string, myChannels: MyChannelModel[]) => {
|
||||
const unreads = subscriptions.get(serverUrl);
|
||||
if (unreads) {
|
||||
let mentions = 0;
|
||||
let messages = 0;
|
||||
myChannels.forEach((myChannel) => {
|
||||
mentions += myChannel.mentionsCount;
|
||||
messages += myChannel.messageCount;
|
||||
});
|
||||
|
||||
unreads.mentions = mentions;
|
||||
unreads.messages = messages;
|
||||
subscriptions.set(serverUrl, unreads);
|
||||
updateTotal();
|
||||
}
|
||||
};
|
||||
|
||||
const serversObserver = async (servers: ServersModel[]) => {
|
||||
servers.forEach((server) => {
|
||||
const serverUrl = server.url;
|
||||
if (server.lastActiveAt) {
|
||||
const sdb = DatabaseManager.serverDatabases[serverUrl];
|
||||
if (sdb?.database) {
|
||||
const subscription = sdb.database.
|
||||
get(MY_CHANNEL).
|
||||
query(Q.on(CHANNEL, Q.where('delete_at', Q.eq(0)))).
|
||||
observeWithColumns(['mentions_count', 'message_count']).
|
||||
subscribe(unreadsSubscription.bind(undefined, serverUrl));
|
||||
if (!subscriptions.has(serverUrl)) {
|
||||
const unreads: UnreadSubscription = {
|
||||
mentions: 0,
|
||||
messages: 0,
|
||||
subscription,
|
||||
};
|
||||
subscriptions.set(serverUrl, unreads);
|
||||
}
|
||||
}
|
||||
|
||||
// subscribe and listen for unreads and mentions
|
||||
} else if (subscriptions.has(serverUrl)) {
|
||||
// logout from server, remove the subscription
|
||||
subscriptions.delete(serverUrl);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const subscription = db?.
|
||||
get(SERVERS).
|
||||
query().
|
||||
observeWithColumns(['last_active_at']).
|
||||
subscribe(serversObserver);
|
||||
|
||||
return () => {
|
||||
subscription?.unsubscribe();
|
||||
subscriptions.forEach((unreads) => {
|
||||
unreads.subscription?.unsubscribe();
|
||||
});
|
||||
};
|
||||
}, []);
|
||||
|
||||
let unreadStyle;
|
||||
let text: string | number = '';
|
||||
let size = 16;
|
||||
if (total.mentions) {
|
||||
text = total.mentions > 99 ? '99+' : total.mentions;
|
||||
unreadStyle = style.mentions;
|
||||
} else if (total.messages) {
|
||||
unreadStyle = style.unread;
|
||||
size = 12;
|
||||
}
|
||||
|
||||
return (
|
||||
<View>
|
||||
<CompassIcon
|
||||
size={28}
|
||||
name='home-variant-outline'
|
||||
color={isFocused ? theme.buttonBg : changeOpacity(theme.centerChannelColor, 0.48)}
|
||||
/>
|
||||
<Badge
|
||||
style={[unreadStyle]}
|
||||
visible={!isFocused && Boolean(unreadStyle)}
|
||||
size={size}
|
||||
>
|
||||
{text}
|
||||
</Badge>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default Home;
|
||||
172
app/screens/home/tab_bar/index.tsx
Normal file
172
app/screens/home/tab_bar/index.tsx
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import {DeviceEventEmitter, View, TouchableOpacity, useWindowDimensions} from 'react-native';
|
||||
import Animated, {useAnimatedStyle, withTiming} from 'react-native-reanimated';
|
||||
import {Shadow} from 'react-native-neomorph-shadows';
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context';
|
||||
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
|
||||
import Account from './account';
|
||||
import Home from './home';
|
||||
import Mentions from './mentions';
|
||||
import Search from './search';
|
||||
|
||||
import type {BottomTabBarProps} from '@react-navigation/bottom-tabs';
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||
container: {
|
||||
backgroundColor: theme.centerChannelBg,
|
||||
alignContent: 'center',
|
||||
flexDirection: 'row',
|
||||
height: 52,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
item: {
|
||||
alignItems: 'center',
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
separator: {
|
||||
borderTopColor: changeOpacity(theme.centerChannelColor, 0.08),
|
||||
borderTopWidth: 0.5,
|
||||
},
|
||||
slider: {
|
||||
backgroundColor: theme.buttonBg,
|
||||
borderBottomLeftRadius: 4,
|
||||
borderBottomRightRadius: 4,
|
||||
width: 48,
|
||||
height: 4,
|
||||
},
|
||||
sliderContainer: {
|
||||
height: 4,
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 10,
|
||||
alignItems: 'center',
|
||||
},
|
||||
}));
|
||||
|
||||
const TabComponents: Record<string, any> = {
|
||||
Account,
|
||||
Home,
|
||||
Mentions,
|
||||
Search,
|
||||
};
|
||||
|
||||
function TabBar({state, descriptors, navigation, theme}: BottomTabBarProps & {theme: Theme}) {
|
||||
const [visible, setVisible] = useState<boolean|undefined>();
|
||||
const {width} = useWindowDimensions();
|
||||
const tabWidth = width / state.routes.length;
|
||||
const style = getStyleSheet(theme);
|
||||
const safeareaInsets = useSafeAreaInsets();
|
||||
|
||||
useEffect(() => {
|
||||
const event = DeviceEventEmitter.addListener('tabBarVisible', (show) => {
|
||||
setVisible(show);
|
||||
});
|
||||
|
||||
return () => event.remove();
|
||||
}, []);
|
||||
|
||||
const transform = useAnimatedStyle(() => {
|
||||
const translateX = withTiming(state.index * tabWidth, {duration: 150});
|
||||
return {
|
||||
transform: [{translateX}],
|
||||
};
|
||||
}, [state.index]);
|
||||
|
||||
const animatedStyle = useAnimatedStyle(() => {
|
||||
if (visible === undefined) {
|
||||
return {transform: [{translateY: -safeareaInsets.bottom}]};
|
||||
}
|
||||
|
||||
const height = visible ? withTiming(-safeareaInsets.bottom, {duration: 200}) : withTiming(52 + safeareaInsets.bottom, {duration: 150});
|
||||
return {
|
||||
transform: [{translateY: height}],
|
||||
};
|
||||
}, [visible]);
|
||||
|
||||
return (
|
||||
<Animated.View style={[style.container, style.separator, animatedStyle]}>
|
||||
<Shadow
|
||||
style={{
|
||||
position: 'absolute',
|
||||
height: 90,
|
||||
width,
|
||||
shadowColor: 'rgba(61, 60, 64, 0.08)',
|
||||
shadowOffset: {width: 0, height: -0.5},
|
||||
shadowOpacity: 1,
|
||||
shadowRadius: 6,
|
||||
backgroundColor: theme.centerChannelBg,
|
||||
}}
|
||||
/>
|
||||
<Animated.View
|
||||
style={[
|
||||
style.sliderContainer,
|
||||
{width: tabWidth - 20},
|
||||
transform,
|
||||
]}
|
||||
>
|
||||
<View style={style.slider}/>
|
||||
</Animated.View>
|
||||
{state.routes.map((route, index) => {
|
||||
const {options} = descriptors[route.key];
|
||||
|
||||
const isFocused = state.index === index;
|
||||
|
||||
const onPress = () => {
|
||||
const lastTab = state.history[state.history.length - 1];
|
||||
const lastIndex = state.routes.findIndex((r) => r.key === lastTab.key);
|
||||
const direction = lastIndex < index ? 'right' : 'left';
|
||||
const event = navigation.emit({
|
||||
type: 'tabPress',
|
||||
target: route.key,
|
||||
canPreventDefault: true,
|
||||
});
|
||||
|
||||
if (!isFocused && !event.defaultPrevented) {
|
||||
// The `merge: true` option makes sure that the params inside the tab screen are preserved
|
||||
navigation.navigate({params: {...route.params, direction}, name: route.name, merge: true});
|
||||
}
|
||||
};
|
||||
|
||||
const onLongPress = () => {
|
||||
navigation.emit({
|
||||
type: 'tabLongPress',
|
||||
target: route.key,
|
||||
});
|
||||
};
|
||||
|
||||
const renderOption = () => {
|
||||
const Component = TabComponents[route.name];
|
||||
const props = {isFocused, theme};
|
||||
if (Component) {
|
||||
return <Component {...props}/>;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={route.name}
|
||||
accessibilityRole='button'
|
||||
accessibilityState={isFocused ? {selected: true} : {}}
|
||||
accessibilityLabel={options.tabBarAccessibilityLabel}
|
||||
testID={options.tabBarTestID}
|
||||
onPress={onPress}
|
||||
onLongPress={onLongPress}
|
||||
style={style.item}
|
||||
>
|
||||
{renderOption()}
|
||||
</TouchableOpacity>
|
||||
);
|
||||
})}
|
||||
</Animated.View>
|
||||
);
|
||||
}
|
||||
|
||||
export default TabBar;
|
||||
27
app/screens/home/tab_bar/mentions.tsx
Normal file
27
app/screens/home/tab_bar/mentions.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {View} from 'react-native';
|
||||
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import {changeOpacity} from '@utils/theme';
|
||||
|
||||
type Props = {
|
||||
isFocused: boolean;
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
const Mentions = ({isFocused, theme}: Props) => {
|
||||
return (
|
||||
<View>
|
||||
<CompassIcon
|
||||
size={28}
|
||||
name='at'
|
||||
color={isFocused ? theme.buttonBg : changeOpacity(theme.centerChannelColor, 0.48)}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default Mentions;
|
||||
27
app/screens/home/tab_bar/search.tsx
Normal file
27
app/screens/home/tab_bar/search.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {View} from 'react-native';
|
||||
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import {changeOpacity} from '@utils/theme';
|
||||
|
||||
type Props = {
|
||||
isFocused: boolean;
|
||||
theme: Theme;
|
||||
}
|
||||
|
||||
const Search = ({isFocused, theme}: Props) => {
|
||||
return (
|
||||
<View>
|
||||
<CompassIcon
|
||||
size={28}
|
||||
name='magnify'
|
||||
color={isFocused ? theme.buttonBg : changeOpacity(theme.centerChannelColor, 0.48)}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default Search;
|
||||
|
|
@ -51,7 +51,7 @@ Navigation.setLazyComponentRegistrator((screenName) => {
|
|||
let screen: any|undefined;
|
||||
let extraStyles: StyleProp<ViewStyle>;
|
||||
switch (screenName) {
|
||||
case 'About':
|
||||
case Screens.ABOUT:
|
||||
screen = withServerDatabase(require('@screens/about').default);
|
||||
break;
|
||||
// case 'AddReaction':
|
||||
|
|
@ -60,9 +60,12 @@ Navigation.setLazyComponentRegistrator((screenName) => {
|
|||
// case 'AdvancedSettings':
|
||||
// screen = require('@screens/settings/advanced_settings').default;
|
||||
// break;
|
||||
case 'BottomSheet':
|
||||
case Screens.BOTTOM_SHEET:
|
||||
screen = require('@screens/bottom_sheet').default;
|
||||
break;
|
||||
case Screens.CHANNEL:
|
||||
screen = withServerDatabase(require('@screens/channel').default);
|
||||
break;
|
||||
// case 'ChannelAddMembers':
|
||||
// screen = require('@screens/channel_add_members').default;
|
||||
// break;
|
||||
|
|
@ -108,7 +111,7 @@ Navigation.setLazyComponentRegistrator((screenName) => {
|
|||
// case 'FlaggedPosts':
|
||||
// screen = require('@screens/flagged_posts').default;
|
||||
// break;
|
||||
case 'ForgotPassword':
|
||||
case Screens.FORGOT_PASSWORD:
|
||||
screen = require('@screens/forgot_password').default;
|
||||
break;
|
||||
// case 'Gallery':
|
||||
|
|
@ -117,10 +120,10 @@ Navigation.setLazyComponentRegistrator((screenName) => {
|
|||
// case 'InteractiveDialog':
|
||||
// screen = require('@screens/interactive_dialog').default;
|
||||
// break;
|
||||
case 'Login':
|
||||
case Screens.LOGIN:
|
||||
screen = require('@screens/login').default;
|
||||
break;
|
||||
case 'LoginOptions':
|
||||
case Screens.LOGIN_OPTIONS:
|
||||
screen = require('@screens/login_options').default;
|
||||
break;
|
||||
// case 'LongPost':
|
||||
|
|
@ -129,7 +132,7 @@ Navigation.setLazyComponentRegistrator((screenName) => {
|
|||
// case 'MainSidebar':
|
||||
// screen = require('app/components/sidebars/main').default;
|
||||
// break;
|
||||
case 'MFA':
|
||||
case Screens.MFA:
|
||||
screen = require('@screens/mfa').default;
|
||||
break;
|
||||
// case 'MoreChannels':
|
||||
|
|
@ -196,9 +199,9 @@ Navigation.setLazyComponentRegistrator((screenName) => {
|
|||
// case 'SidebarSettings':
|
||||
// screen = require('@screens/settings/sidebar').default;
|
||||
// break;
|
||||
case 'SSO':
|
||||
screen = require('@screens/sso').default;
|
||||
break;
|
||||
case Screens.SSO:
|
||||
screen = require('@screens/sso').default;
|
||||
break;
|
||||
// case 'Table':
|
||||
// screen = require('@screens/table').default;
|
||||
// break;
|
||||
|
|
@ -225,9 +228,8 @@ Navigation.setLazyComponentRegistrator((screenName) => {
|
|||
});
|
||||
|
||||
export function registerScreens() {
|
||||
const channelScreen = require('@screens/channel').default;
|
||||
const homeScreen = require('@screens/home').default;
|
||||
const serverScreen = require('@screens/server').default;
|
||||
|
||||
Navigation.registerComponent(Screens.CHANNEL, () => withSafeAreaInsets(withGestures(withIntl(withServerDatabase(withManagedConfig(channelScreen))), undefined)));
|
||||
Navigation.registerComponent(Screens.SERVER, () => withIntl(withManagedConfig(serverScreen)));
|
||||
Navigation.registerComponent(Screens.HOME, () => withSafeAreaInsets(withGestures(withIntl(withServerDatabase(withManagedConfig(homeScreen))), undefined)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ exports[`Login Login screen should match snapshot 1`] = `
|
|||
onChangeText={[Function]}
|
||||
onSubmitEditing={[Function]}
|
||||
placeholder="Email or Username"
|
||||
placeholderTextColor="rgba(61,60,64,0.5)"
|
||||
placeholderTextColor="rgba(63,67,80,0.5)"
|
||||
rejectResponderTermination={true}
|
||||
returnKeyType="next"
|
||||
style={
|
||||
|
|
@ -95,7 +95,7 @@ exports[`Login Login screen should match snapshot 1`] = `
|
|||
"borderColor": "gainsboro",
|
||||
"borderRadius": 3,
|
||||
"borderWidth": 1,
|
||||
"color": "#3d3c40",
|
||||
"color": "#3f4350",
|
||||
"fontSize": 16,
|
||||
"height": 45,
|
||||
"marginBottom": 5,
|
||||
|
|
@ -115,7 +115,7 @@ exports[`Login Login screen should match snapshot 1`] = `
|
|||
onChangeText={[Function]}
|
||||
onSubmitEditing={[Function]}
|
||||
placeholder="Password"
|
||||
placeholderTextColor="rgba(61,60,64,0.5)"
|
||||
placeholderTextColor="rgba(63,67,80,0.5)"
|
||||
rejectResponderTermination={true}
|
||||
returnKeyType="go"
|
||||
secureTextEntry={true}
|
||||
|
|
@ -125,7 +125,7 @@ exports[`Login Login screen should match snapshot 1`] = `
|
|||
"borderColor": "gainsboro",
|
||||
"borderRadius": 3,
|
||||
"borderWidth": 1,
|
||||
"color": "#3d3c40",
|
||||
"color": "#3f4350",
|
||||
"fontSize": 16,
|
||||
"height": 45,
|
||||
"marginBottom": 5,
|
||||
|
|
@ -152,7 +152,7 @@ exports[`Login Login screen should match snapshot 1`] = `
|
|||
Object {
|
||||
"alignItems": "center",
|
||||
"alignSelf": "stretch",
|
||||
"borderColor": "#166de0",
|
||||
"borderColor": "#1c58d9",
|
||||
"borderRadius": 3,
|
||||
"borderWidth": 1,
|
||||
"marginTop": 10,
|
||||
|
|
@ -166,7 +166,7 @@ exports[`Login Login screen should match snapshot 1`] = `
|
|||
style={
|
||||
Array [
|
||||
Object {
|
||||
"color": "#166de0",
|
||||
"color": "#1c58d9",
|
||||
"fontSize": 17,
|
||||
"textAlign": "center",
|
||||
},
|
||||
|
|
@ -199,7 +199,7 @@ exports[`Login Login screen should match snapshot 1`] = `
|
|||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "#2389d7",
|
||||
"color": "#386fe5",
|
||||
}
|
||||
}
|
||||
testID="login.forgot"
|
||||
|
|
|
|||
|
|
@ -460,6 +460,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
|||
fontSize: 17,
|
||||
},
|
||||
header: {
|
||||
color: theme.centerChannelColor,
|
||||
textAlign: 'center',
|
||||
marginTop: 15,
|
||||
marginBottom: 15,
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ describe('Login', () => {
|
|||
license: {
|
||||
IsLicensed: 'false',
|
||||
},
|
||||
theme: Preferences.THEMES.default,
|
||||
theme: Preferences.THEMES.denim,
|
||||
serverUrl: 'https://locahost:8065',
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ const getStyles = makeStyleSheetFromTheme((theme: Theme) => ({
|
|||
flex: 1,
|
||||
},
|
||||
header: {
|
||||
color: theme.centerChannelColor,
|
||||
textAlign: 'center',
|
||||
marginTop: 15,
|
||||
marginBottom: 15,
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ exports[`*** MFA Screen *** MFA screen should match snapshot 1`] = `
|
|||
style={
|
||||
Array [
|
||||
Object {
|
||||
"color": "#3f4350",
|
||||
"fontSize": 32,
|
||||
"fontWeight": "600",
|
||||
"marginBottom": 15,
|
||||
|
|
@ -72,7 +73,7 @@ exports[`*** MFA Screen *** MFA screen should match snapshot 1`] = `
|
|||
"textAlign": "center",
|
||||
},
|
||||
Object {
|
||||
"color": "rgba(61,60,64,0.6)",
|
||||
"color": "rgba(63,67,80,0.6)",
|
||||
"fontSize": 20,
|
||||
"fontWeight": "400",
|
||||
},
|
||||
|
|
@ -86,7 +87,7 @@ exports[`*** MFA Screen *** MFA screen should match snapshot 1`] = `
|
|||
style={
|
||||
Array [
|
||||
Object {
|
||||
"color": "#fd5960",
|
||||
"color": "#d24b4e",
|
||||
"fontSize": 12,
|
||||
"marginBottom": 15,
|
||||
"marginTop": 15,
|
||||
|
|
@ -108,7 +109,7 @@ exports[`*** MFA Screen *** MFA screen should match snapshot 1`] = `
|
|||
onChangeText={[Function]}
|
||||
onSubmitEditing={[Function]}
|
||||
placeholder="MFA Token"
|
||||
placeholderTextColor="rgba(61,60,64,0.5)"
|
||||
placeholderTextColor="rgba(63,67,80,0.5)"
|
||||
rejectResponderTermination={true}
|
||||
returnKeyType="go"
|
||||
style={
|
||||
|
|
@ -117,7 +118,7 @@ exports[`*** MFA Screen *** MFA screen should match snapshot 1`] = `
|
|||
"borderColor": "gainsboro",
|
||||
"borderRadius": 3,
|
||||
"borderWidth": 1,
|
||||
"color": "#3d3c40",
|
||||
"color": "#3f4350",
|
||||
"fontSize": 16,
|
||||
"height": 45,
|
||||
"marginBottom": 5,
|
||||
|
|
@ -144,7 +145,7 @@ exports[`*** MFA Screen *** MFA screen should match snapshot 1`] = `
|
|||
Object {
|
||||
"alignItems": "center",
|
||||
"alignSelf": "stretch",
|
||||
"borderColor": "#166de0",
|
||||
"borderColor": "#1c58d9",
|
||||
"borderRadius": 3,
|
||||
"borderWidth": 1,
|
||||
"marginTop": 10,
|
||||
|
|
@ -157,7 +158,7 @@ exports[`*** MFA Screen *** MFA screen should match snapshot 1`] = `
|
|||
<Text
|
||||
style={
|
||||
Object {
|
||||
"color": "#166de0",
|
||||
"color": "#1c58d9",
|
||||
"fontSize": 17,
|
||||
"textAlign": "center",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,6 +201,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
|||
color: theme.centerChannelColor,
|
||||
},
|
||||
header: {
|
||||
color: theme.centerChannelColor,
|
||||
textAlign: 'center',
|
||||
marginTop: 15,
|
||||
marginBottom: 15,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ describe('*** MFA Screen ***', () => {
|
|||
password: 'passwd',
|
||||
license: {},
|
||||
serverUrl: 'https://locahost:8065',
|
||||
theme: Preferences.THEMES.default,
|
||||
theme: Preferences.THEMES.denim,
|
||||
};
|
||||
|
||||
test('MFA screen should match snapshot', () => {
|
||||
|
|
|
|||
15
app/screens/modal/index.tsx
Normal file
15
app/screens/modal/index.tsx
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {Text, View} from 'react-native';
|
||||
|
||||
const Modal = () => {
|
||||
return (
|
||||
<View style={{backgroundColor: '#ffffff', flex: 1}}>
|
||||
<Text>{'Modal screen'}</Text>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default Modal;
|
||||
|
|
@ -2,23 +2,30 @@
|
|||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Appearance, DeviceEventEmitter, Keyboard, Platform} from 'react-native';
|
||||
import {Layout, Navigation, Options, OptionsModalPresentationStyle} from 'react-native-navigation';
|
||||
import {Navigation, Options, OptionsModalPresentationStyle} from 'react-native-navigation';
|
||||
import merge from 'deepmerge';
|
||||
|
||||
import {Navigation as NavigationConstants, Preferences, Screens} from '@constants';
|
||||
|
||||
import {Device, Preferences, Screens} from '@constants';
|
||||
import NavigationConstants from '@constants/navigation';
|
||||
import EphemeralStore from '@store/ephemeral_store';
|
||||
|
||||
import type {LaunchProps} from '@typings/launch';
|
||||
|
||||
Navigation.setDefaultOptions({
|
||||
layout: {
|
||||
|
||||
//@ts-expect-error all not defined in type definition
|
||||
orientation: [Device.IS_TABLET ? 'all' : 'portrait'],
|
||||
},
|
||||
});
|
||||
|
||||
function getThemeFromState() {
|
||||
if (EphemeralStore.theme) {
|
||||
return EphemeralStore.theme;
|
||||
}
|
||||
if (Appearance.getColorScheme() === 'dark') {
|
||||
return Preferences.THEMES.windows10;
|
||||
return Preferences.THEMES.onyx;
|
||||
}
|
||||
return Preferences.THEMES.default;
|
||||
return Preferences.THEMES.denim;
|
||||
}
|
||||
|
||||
export function resetToChannel(passProps = {}) {
|
||||
|
|
@ -29,8 +36,8 @@ export function resetToChannel(passProps = {}) {
|
|||
const stack = {
|
||||
children: [{
|
||||
component: {
|
||||
id: Screens.CHANNEL,
|
||||
name: Screens.CHANNEL,
|
||||
id: Screens.HOME,
|
||||
name: Screens.HOME,
|
||||
passProps,
|
||||
options: {
|
||||
layout: {
|
||||
|
|
@ -55,34 +62,8 @@ export function resetToChannel(passProps = {}) {
|
|||
}],
|
||||
};
|
||||
|
||||
const platformStack: Layout = {stack};
|
||||
|
||||
// if (Platform.OS === 'android') {
|
||||
// platformStack = {
|
||||
// sideMenu: {
|
||||
// left: {
|
||||
// component: {
|
||||
// id: Screens.MAIN_SIDEBAR,
|
||||
// name: Screens.MAIN_SIDEBAR,
|
||||
// },
|
||||
// },
|
||||
// center: {
|
||||
// stack,
|
||||
// },
|
||||
// right: {
|
||||
// component: {
|
||||
// id: Screens.SETTINGS_SIDEBAR,
|
||||
// name: Screens.SETTINGS_SIDEBAR,
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// };
|
||||
// }
|
||||
|
||||
Navigation.setRoot({
|
||||
root: {
|
||||
...platformStack,
|
||||
},
|
||||
root: {stack},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -177,6 +158,7 @@ export function resetToTeams(name: string, title: string, passProps = {}, option
|
|||
export function goToScreen(name: string, title: string, passProps = {}, options = {}) {
|
||||
const theme = getThemeFromState();
|
||||
const componentId = EphemeralStore.getNavigationTopComponentId();
|
||||
DeviceEventEmitter.emit('tabBarVisible', false);
|
||||
const defaultOptions = {
|
||||
layout: {
|
||||
componentBackgroundColor: theme.centerChannelBg,
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@ import React, {useCallback, useEffect, useRef, useState} from 'react';
|
|||
import {useIntl} from 'react-intl';
|
||||
import {
|
||||
ActivityIndicator, EventSubscription, Image, Keyboard, KeyboardAvoidingView,
|
||||
Platform, StatusBar, StyleSheet, TextInput, TouchableWithoutFeedback, View,
|
||||
Platform, StatusBar, StatusBarStyle, StyleSheet, TextInput, TouchableWithoutFeedback, View,
|
||||
} from 'react-native';
|
||||
import Button from 'react-native-button';
|
||||
import {Navigation, NavigationFunctionComponent} from 'react-native-navigation';
|
||||
import {SafeAreaView} from 'react-native-safe-area-context';
|
||||
import tinyColor from 'tinycolor2';
|
||||
|
||||
import {doPing} from '@actions/remote/general';
|
||||
import {fetchConfigAndLicense} from '@actions/remote/systems';
|
||||
|
|
@ -257,8 +258,12 @@ const Server: NavigationFunctionComponent = ({componentId, extra, launchType, la
|
|||
);
|
||||
}
|
||||
|
||||
const barStyle = Platform.OS === 'android' ? 'light-content' : 'dark-content';
|
||||
const statusColor = tinyColor(theme.centerChannelBg);
|
||||
const inputDisabled = managedConfig.allowOtherServers === 'false' || connecting;
|
||||
let barStyle: StatusBarStyle = 'light-content';
|
||||
if (Platform.OS === 'ios' && statusColor.isLight()) {
|
||||
barStyle = 'dark-content';
|
||||
}
|
||||
|
||||
const inputStyle = [styles.inputBox];
|
||||
if (inputDisabled) {
|
||||
|
|
@ -333,13 +338,16 @@ const Server: NavigationFunctionComponent = ({componentId, extra, launchType, la
|
|||
}
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
<AppVersion/>
|
||||
<AppVersion textStyle={styles.appInfo}/>
|
||||
</KeyboardAvoidingView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||
appInfo: {
|
||||
color: theme.centerChannelColor,
|
||||
},
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: theme.centerChannelBg,
|
||||
|
|
@ -387,6 +395,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
|||
resizeMode: 'contain',
|
||||
},
|
||||
header: {
|
||||
color: theme.centerChannelColor,
|
||||
textAlign: 'center',
|
||||
marginTop: 15,
|
||||
marginBottom: 15,
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ describe('SSO', () => {
|
|||
IsLicensed: 'true',
|
||||
},
|
||||
ssoType: 'GITLAB',
|
||||
theme: Preferences.THEMES.default,
|
||||
theme: Preferences.THEMES.denim,
|
||||
serverUrl: 'https://locahost:8065',
|
||||
launchType: LaunchType.Normal,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ describe('SSO with redirect url', () => {
|
|||
loginUrl: '',
|
||||
serverUrl: 'http://localhost:8065',
|
||||
setLoginError: jest.fn(),
|
||||
theme: Preferences.THEMES.default,
|
||||
theme: Preferences.THEMES.denim,
|
||||
};
|
||||
|
||||
test('should show message when user navigates to the page', () => {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ class EphemeralStore {
|
|||
navigationModalStack: string[] = [];
|
||||
theme: Theme | undefined;
|
||||
|
||||
getNavigationTopComponentId = () => this.navigationComponentIdStack[0];
|
||||
getNavigationTopComponentId = () => {
|
||||
return this.navigationComponentIdStack[0];
|
||||
}
|
||||
|
||||
clearNavigationComponents = () => {
|
||||
this.navigationComponentIdStack = [];
|
||||
|
|
@ -30,8 +32,8 @@ class EphemeralStore {
|
|||
|
||||
addToNavigationComponentIdStack = (componentId: string) => {
|
||||
const index = this.navigationComponentIdStack.indexOf(componentId);
|
||||
if (index > 0) {
|
||||
this.navigationComponentIdStack.slice(index, 1);
|
||||
if (index >= 0) {
|
||||
this.navigationComponentIdStack = this.navigationComponentIdStack.slice(index, 1);
|
||||
}
|
||||
|
||||
this.navigationComponentIdStack.unshift(componentId);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
import {Dimensions} from 'react-native';
|
||||
|
||||
import {Device} from '@constants';
|
||||
import {View} from '@constants';
|
||||
import {IMAGE_MAX_HEIGHT, IMAGE_MIN_DIMENSION, MAX_GIF_SIZE, VIEWPORT_IMAGE_OFFSET, VIEWPORT_IMAGE_REPLY_OFFSET} from '@constants/image';
|
||||
|
||||
export const calculateDimensions = (height: number, width: number, viewPortWidth = 0, viewPortHeight = 0) => {
|
||||
|
|
@ -45,12 +45,12 @@ export const calculateDimensions = (height: number, width: number, viewPortWidth
|
|||
};
|
||||
};
|
||||
|
||||
export function getViewPortWidth(isReplyPost: boolean, permanentSidebar = false) {
|
||||
export function getViewPortWidth(isReplyPost: boolean, tabletOffset = false) {
|
||||
const {width, height} = Dimensions.get('window');
|
||||
let portraitPostWidth = Math.min(width, height) - VIEWPORT_IMAGE_OFFSET;
|
||||
|
||||
if (permanentSidebar) {
|
||||
portraitPostWidth -= Device.TABLET_WIDTH;
|
||||
if (tabletOffset) {
|
||||
portraitPostWidth -= View.TABLET.SIDEBAR_WIDTH;
|
||||
}
|
||||
|
||||
if (isReplyPost) {
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ function blendComponent(background: number, foreground: number, opacity: number)
|
|||
return ((1 - opacity) * background) + (opacity * foreground);
|
||||
}
|
||||
|
||||
export function blendColors(background: string, foreground: string, opacity: number): string {
|
||||
export function blendColors(background: string, foreground: string, opacity: number, hex = false): string {
|
||||
const backgroundComponents = getComponents(background);
|
||||
const foregroundComponents = getComponents(foreground);
|
||||
|
||||
|
|
@ -186,5 +186,23 @@ export function blendColors(background: string, foreground: string, opacity: num
|
|||
opacity,
|
||||
);
|
||||
|
||||
if (hex) {
|
||||
let r = red.toString(16);
|
||||
let g = green.toString(16);
|
||||
let b = blue.toString(16);
|
||||
|
||||
if (r.length === 1) {
|
||||
r = '0' + r;
|
||||
}
|
||||
if (g.length === 1) {
|
||||
g = '0' + g;
|
||||
}
|
||||
if (b.length === 1) {
|
||||
b = '0' + b;
|
||||
}
|
||||
|
||||
return `#${r + g + b}`;
|
||||
}
|
||||
|
||||
return `rgba(${red},${green},${blue},${alpha})`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,41 +1,34 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {Preferences} from '@constants';
|
||||
import {getKeyboardAppearanceFromTheme} from '@utils/theme';
|
||||
|
||||
const themes = Preferences.THEMES;
|
||||
|
||||
describe('getKeyboardAppearanceFromTheme', () => {
|
||||
const themes: Partial<Theme> = [
|
||||
{
|
||||
centerChannelBg: '#ffffff', // Mattermost
|
||||
},
|
||||
{
|
||||
centerChannelBg: '#f2f4f8', // Organization
|
||||
},
|
||||
{
|
||||
centerChannelBg: '#2f3e4e', // Mattermost Dark
|
||||
},
|
||||
{
|
||||
centerChannelBg: '#1f1f1f', // Windows Dark
|
||||
},
|
||||
];
|
||||
it('should return "light" keyboard appearance for centerChannelBg="#ffffff"', () => {
|
||||
const keyboardAppearance = getKeyboardAppearanceFromTheme(themes.denim);
|
||||
expect(keyboardAppearance).toBe('light');
|
||||
});
|
||||
|
||||
it('should return "light" keyboard appearance for centerChannelBg="#ffffff"', () => {
|
||||
const keyboardAppearance = getKeyboardAppearanceFromTheme(themes[0]);
|
||||
const keyboardAppearance = getKeyboardAppearanceFromTheme(themes.sapphire);
|
||||
expect(keyboardAppearance).toBe('light');
|
||||
});
|
||||
|
||||
it('should return "light" keyboard appearance for centerChannelBg="#f2f4f8"', () => {
|
||||
const keyboardAppearance = getKeyboardAppearanceFromTheme(themes[1]);
|
||||
it('should return "dark" keyboard appearance for centerChannelBg="#ffffff"', () => {
|
||||
const keyboardAppearance = getKeyboardAppearanceFromTheme(themes.quartz);
|
||||
expect(keyboardAppearance).toBe('light');
|
||||
});
|
||||
|
||||
it('should return "dark" keyboard appearance for centerChannelBg="#2f3e4e"', () => {
|
||||
const keyboardAppearance = getKeyboardAppearanceFromTheme(themes[2]);
|
||||
it('should return "dark" keyboard appearance for centerChannelBg="#0a111f"', () => {
|
||||
const keyboardAppearance = getKeyboardAppearanceFromTheme(themes.indigo);
|
||||
expect(keyboardAppearance).toBe('dark');
|
||||
});
|
||||
|
||||
it('should return "dark" keyboard appearance for centerChannelBg="#1f1f1f"', () => {
|
||||
const keyboardAppearance = getKeyboardAppearanceFromTheme(themes[3]);
|
||||
it('should return "dark" keyboard appearance for centerChannelBg="#090a0b"', () => {
|
||||
const keyboardAppearance = getKeyboardAppearanceFromTheme(themes.onyx);
|
||||
expect(keyboardAppearance).toBe('dark');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Binary file not shown.
25
index.ts
25
index.ts
|
|
@ -5,7 +5,7 @@ import {DeviceEventEmitter, Platform} from 'react-native';
|
|||
import 'react-native-gesture-handler';
|
||||
import {ComponentDidAppearEvent, ComponentDidDisappearEvent, Navigation} from 'react-native-navigation';
|
||||
|
||||
import {Navigation as NavigationConstants, Screens} from './app/constants';
|
||||
import {Screens} from './app/constants';
|
||||
import DatabaseManager from './app/database/manager';
|
||||
import {getAllServerCredentials} from './app/init/credentials';
|
||||
import GlobalEventHandler from './app/init/global_event_handler';
|
||||
|
|
@ -65,28 +65,21 @@ Navigation.events().registerAppLaunchedListener(async () => {
|
|||
const registerNavigationListeners = () => {
|
||||
Navigation.events().registerComponentDidAppearListener(componentDidAppearListener);
|
||||
Navigation.events().registerComponentDidDisappearListener(componentDidDisappearListener);
|
||||
Navigation.events().registerComponentWillAppearListener(componentWillAppear);
|
||||
};
|
||||
|
||||
function componentWillAppear({componentId}: ComponentDidAppearEvent) {
|
||||
if (componentId === Screens.HOME) {
|
||||
DeviceEventEmitter.emit('tabBarVisible', true);
|
||||
}
|
||||
}
|
||||
|
||||
function componentDidAppearListener({componentId}: ComponentDidAppearEvent) {
|
||||
EphemeralStore.addNavigationComponentId(componentId);
|
||||
|
||||
switch (componentId) {
|
||||
case 'MainSidebar':
|
||||
DeviceEventEmitter.emit(NavigationConstants.MAIN_SIDEBAR_DID_OPEN);
|
||||
DeviceEventEmitter.emit(NavigationConstants.BLUR_POST_DRAFT);
|
||||
break;
|
||||
case 'SettingsSidebar':
|
||||
DeviceEventEmitter.emit(NavigationConstants.BLUR_POST_DRAFT);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function componentDidDisappearListener({componentId}: ComponentDidDisappearEvent) {
|
||||
if (componentId !== Screens.CHANNEL) {
|
||||
if (componentId !== Screens.HOME) {
|
||||
EphemeralStore.removeNavigationComponentId(componentId);
|
||||
}
|
||||
|
||||
if (componentId === 'MainSidebar') {
|
||||
DeviceEventEmitter.emit(NavigationConstants.MAIN_SIDEBAR_DID_CLOSE);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -334,6 +334,8 @@ PODS:
|
|||
- React-cxxreact (= 0.64.2)
|
||||
- React-jsi (= 0.64.2)
|
||||
- React-perflogger (= 0.64.2)
|
||||
- ReactNativeART (1.2.0):
|
||||
- React
|
||||
- ReactNativeExceptionHandler (2.10.10):
|
||||
- React-Core
|
||||
- ReactNativeKeyboardTrackingView (5.7.0):
|
||||
|
|
@ -375,7 +377,7 @@ PODS:
|
|||
- React-Core
|
||||
- RNReactNativeHapticFeedback (1.11.0):
|
||||
- React-Core
|
||||
- RNReanimated (2.2.0):
|
||||
- RNReanimated (2.3.0-alpha.2):
|
||||
- DoubleConversion
|
||||
- FBLazyVector
|
||||
- FBReactNativeSpec
|
||||
|
|
@ -407,6 +409,9 @@ PODS:
|
|||
- RNRudderSdk (1.0.0):
|
||||
- React
|
||||
- Rudder (>= 1.0.20)
|
||||
- RNScreens (3.6.0):
|
||||
- React-Core
|
||||
- React-RCTImage
|
||||
- RNSentry (2.6.1):
|
||||
- React-Core
|
||||
- Sentry (= 7.1.4)
|
||||
|
|
@ -495,6 +500,7 @@ DEPENDENCIES:
|
|||
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
|
||||
- React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`)
|
||||
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
|
||||
- "ReactNativeART (from `../node_modules/@react-native-community/art`)"
|
||||
- ReactNativeExceptionHandler (from `../node_modules/react-native-exception-handler`)
|
||||
- ReactNativeKeyboardTrackingView (from `../node_modules/react-native-keyboard-tracking-view`)
|
||||
- ReactNativeNavigation (from `../node_modules/react-native-navigation`)
|
||||
|
|
@ -512,6 +518,7 @@ DEPENDENCIES:
|
|||
- RNReactNativeHapticFeedback (from `../node_modules/react-native-haptic-feedback`)
|
||||
- RNReanimated (from `../node_modules/react-native-reanimated`)
|
||||
- "RNRudderSdk (from `../node_modules/@rudderstack/rudder-sdk-react-native/ios`)"
|
||||
- RNScreens (from `../node_modules/react-native-screens`)
|
||||
- "RNSentry (from `../node_modules/@sentry/react-native`)"
|
||||
- RNShare (from `../node_modules/react-native-share`)
|
||||
- RNSVG (from `../node_modules/react-native-svg`)
|
||||
|
|
@ -636,6 +643,8 @@ EXTERNAL SOURCES:
|
|||
:path: "../node_modules/react-native/ReactCommon/runtimeexecutor"
|
||||
ReactCommon:
|
||||
:path: "../node_modules/react-native/ReactCommon"
|
||||
ReactNativeART:
|
||||
:path: "../node_modules/@react-native-community/art"
|
||||
ReactNativeExceptionHandler:
|
||||
:path: "../node_modules/react-native-exception-handler"
|
||||
ReactNativeKeyboardTrackingView:
|
||||
|
|
@ -670,6 +679,8 @@ EXTERNAL SOURCES:
|
|||
:path: "../node_modules/react-native-reanimated"
|
||||
RNRudderSdk:
|
||||
:path: "../node_modules/@rudderstack/rudder-sdk-react-native/ios"
|
||||
RNScreens:
|
||||
:path: "../node_modules/react-native-screens"
|
||||
RNSentry:
|
||||
:path: "../node_modules/@sentry/react-native"
|
||||
RNShare:
|
||||
|
|
@ -752,6 +763,7 @@ SPEC CHECKSUMS:
|
|||
React-RCTVibration: 24600e3b1aaa77126989bc58b6747509a1ba14f3
|
||||
React-runtimeexecutor: a9904c6d0218fb9f8b19d6dd88607225927668f9
|
||||
ReactCommon: 149906e01aa51142707a10665185db879898e966
|
||||
ReactNativeART: 78edc68dd4a1e675338cd0cd113319cf3a65f2ab
|
||||
ReactNativeExceptionHandler: b11ff67c78802b2f62eed0e10e75cb1ef7947c60
|
||||
ReactNativeKeyboardTrackingView: 02137fac3b2ebd330d74fa54ead48b14750a2306
|
||||
ReactNativeNavigation: 88128fa06b2c349b613e1e0fd3cdff2c58c01c55
|
||||
|
|
@ -767,8 +779,9 @@ SPEC CHECKSUMS:
|
|||
RNLocalize: 82a569022724d35461e2dc5b5d015a13c3ca995b
|
||||
RNPermissions: 7043bacbf928eae25808275cfe73799b8f618911
|
||||
RNReactNativeHapticFeedback: 653a8c126a0f5e88ce15ffe280b3ff37e1fbb285
|
||||
RNReanimated: 9c13c86454bfd54dab7505c1a054470bfecd2563
|
||||
RNReanimated: daebbd404c0cd9df6daa248d63dd940086bea9ff
|
||||
RNRudderSdk: 9aa881c2bf754dc3b05e392340a5e3663a970f0a
|
||||
RNScreens: eb0dfb2d6b21d2d7f980ad46b14eb306d2f1062e
|
||||
RNSentry: af7873b080a0beb74c020644644d247ef4771644
|
||||
RNShare: 047d42214f875d731bde73a2b67418638af85ad9
|
||||
RNSVG: 551acb6562324b1d52a4e0758f7ca0ec234e278f
|
||||
|
|
|
|||
330
package-lock.json
generated
330
package-lock.json
generated
|
|
@ -21,12 +21,15 @@
|
|||
"@mattermost/react-native-paste-input": "0.1.4",
|
||||
"@nozbe/watermelondb": "0.23.0",
|
||||
"@nozbe/with-observables": "1.4.0",
|
||||
"@react-native-community/art": "1.2.0",
|
||||
"@react-native-community/async-storage": "1.12.1",
|
||||
"@react-native-community/cameraroll": "4.0.4",
|
||||
"@react-native-community/clipboard": "1.5.1",
|
||||
"@react-native-community/masked-view": "0.1.11",
|
||||
"@react-native-community/netinfo": "6.0.0",
|
||||
"@react-native-cookies/cookies": "6.0.8",
|
||||
"@react-navigation/bottom-tabs": "6.0.5",
|
||||
"@react-navigation/native": "6.0.2",
|
||||
"@rudderstack/rudder-sdk-react-native": "1.0.12",
|
||||
"@sentry/react-native": "2.6.1",
|
||||
"@types/mime-db": "1.43.1",
|
||||
|
|
@ -62,11 +65,13 @@
|
|||
"react-native-linear-gradient": "2.5.6",
|
||||
"react-native-localize": "2.1.1",
|
||||
"react-native-navigation": "7.18.1",
|
||||
"react-native-neomorph-shadows": "1.1.2",
|
||||
"react-native-notifications": "4.1.1",
|
||||
"react-native-permissions": "3.0.5",
|
||||
"react-native-reanimated": "2.2.0",
|
||||
"react-native-reanimated": "2.3.0-alpha.2",
|
||||
"react-native-redash": "16.1.1",
|
||||
"react-native-safe-area-context": "3.2.0",
|
||||
"react-native-screens": "3.6.0",
|
||||
"react-native-share": "6.5.0",
|
||||
"react-native-slider": "0.11.0",
|
||||
"react-native-svg": "12.1.1",
|
||||
|
|
@ -4983,6 +4988,20 @@
|
|||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
|
||||
"integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug=="
|
||||
},
|
||||
"node_modules/@react-native-community/art": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-community/art/-/art-1.2.0.tgz",
|
||||
"integrity": "sha512-a+ZcRGl/BzLa89yi33Mbn5SHavsEXqKUMdbfLf3U8MDLElndPqUetoJyGkv63+BcPO49UMWiQRP1YUz6/zfJ+A==",
|
||||
"dependencies": {
|
||||
"art": "^0.10.3",
|
||||
"invariant": "^2.2.4",
|
||||
"prop-types": "^15.7.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-native-community/async-storage": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-community/async-storage/-/async-storage-1.12.1.tgz",
|
||||
|
|
@ -6104,6 +6123,93 @@
|
|||
"resolved": "https://registry.npmjs.org/@react-native/polyfills/-/polyfills-1.0.0.tgz",
|
||||
"integrity": "sha512-0jbp4RxjYopTsIdLl+/Fy2TiwVYHy4mgeu07DG4b/LyM0OS/+lPP5c9sbnt/AMlnF6qz2JRZpPpGw1eMNS6A4w=="
|
||||
},
|
||||
"node_modules/@react-navigation/bottom-tabs": {
|
||||
"version": "6.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-6.0.5.tgz",
|
||||
"integrity": "sha512-GytjJUzacHhe3C24HFrPl881Donrw2m+3JBNqMJALxMRjSA8yY72+l16bZR9YFsrywSHVSbjxIfzqtGb8rIVJg==",
|
||||
"dependencies": {
|
||||
"@react-navigation/elements": "^1.1.0",
|
||||
"color": "^3.1.3",
|
||||
"warn-once": "^0.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@react-navigation/native": "^6.0.0",
|
||||
"react": "*",
|
||||
"react-native": "*",
|
||||
"react-native-safe-area-context": ">= 3.0.0",
|
||||
"react-native-screens": ">= 3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/core": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-6.0.1.tgz",
|
||||
"integrity": "sha512-mVdvBDYdz8uzLQHokmVdX/xC4rS7NIkD1FN/yaGdovVzYApAhM+UGd3w1zskjyCSyXaVHHOwV59ZGVew+84xfQ==",
|
||||
"dependencies": {
|
||||
"@react-navigation/routers": "^6.0.1",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"nanoid": "^3.1.23",
|
||||
"query-string": "^7.0.0",
|
||||
"react-is": "^16.13.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/core/node_modules/escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/elements": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.1.0.tgz",
|
||||
"integrity": "sha512-jZncciZPGuoP6B6f+Wpf6MYSSYy86B2HJDbFTCtT5xZV0w6V9GgCeqvSTOEAxifZrmKl8uDxsr0GrIxgQE8NxA==",
|
||||
"peerDependencies": {
|
||||
"@react-navigation/native": "^6.0.0",
|
||||
"react": "*",
|
||||
"react-native": "*",
|
||||
"react-native-safe-area-context": ">= 3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/native": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-6.0.2.tgz",
|
||||
"integrity": "sha512-HDqEwgvQ4Cu16vz8jQ55lfyNK9CGbECI1wM9cPOcUa+gkOQEDZ/95VFfFjGGflXZs3ybPvGXlMC4ZAyh1CcO6w==",
|
||||
"dependencies": {
|
||||
"@react-navigation/core": "^6.0.1",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"nanoid": "^3.1.23"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/native/node_modules/escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@react-navigation/routers": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-6.0.1.tgz",
|
||||
"integrity": "sha512-5ctB49rmtTRQuTSBVgqMsEzBUjPP2ByUzBjNivA7jmvk+PDCl4oZsiR8KAm/twhxe215GYThfi2vUWXKAg6EEQ==",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.1.23"
|
||||
}
|
||||
},
|
||||
"node_modules/@rudderstack/rudder-sdk-react-native": {
|
||||
"version": "1.0.12",
|
||||
"resolved": "https://registry.npmjs.org/@rudderstack/rudder-sdk-react-native/-/rudder-sdk-react-native-1.0.12.tgz",
|
||||
|
|
@ -8926,6 +9032,14 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/art": {
|
||||
"version": "0.10.3",
|
||||
"resolved": "https://registry.npmjs.org/art/-/art-0.10.3.tgz",
|
||||
"integrity": "sha512-HXwbdofRTiJT6qZX/FnchtldzJjS3vkLJxQilc3Xj+ma2MXjY4UAyQ0ls1XZYVnDvVIBiFZbC6QsvtW86TD6tQ==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/asap": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
|
||||
|
|
@ -14239,6 +14353,14 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/filter-obj": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
|
||||
"integrity": "sha1-mzERErxsYSehbgFsbF1/GeCAXFs=",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/finalhandler": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
|
||||
|
|
@ -24054,8 +24176,6 @@
|
|||
"version": "3.1.23",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
|
||||
"integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
|
|
@ -26072,6 +26192,23 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/query-string": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-7.0.1.tgz",
|
||||
"integrity": "sha512-uIw3iRvHnk9to1blJCG3BTc+Ro56CBowJXKmNNAm3RulvPBzWLRqKSiiDk+IplJhsydwtuNMHi8UGQFcCLVfkA==",
|
||||
"dependencies": {
|
||||
"decode-uri-component": "^0.2.0",
|
||||
"filter-obj": "^1.1.0",
|
||||
"split-on-first": "^1.0.0",
|
||||
"strict-uri-encode": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/querystring": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
|
||||
|
|
@ -26535,6 +26672,15 @@
|
|||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
|
||||
"integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ=="
|
||||
},
|
||||
"node_modules/react-native-neomorph-shadows": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-neomorph-shadows/-/react-native-neomorph-shadows-1.1.2.tgz",
|
||||
"integrity": "sha512-HJ7bBEwuze6TNxz/+1RvaHrrHHYMEZ0itE3hPgGxvst7Jz47K9TnEDiFskjTXMaTxXOCqzPDa9UmUfQK2K15tA==",
|
||||
"dependencies": {
|
||||
"@react-native-community/art": "^1.2.0",
|
||||
"prop-types": "^15.7.2"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-notifications": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-notifications/-/react-native-notifications-4.1.1.tgz",
|
||||
|
|
@ -26567,12 +26713,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/react-native-reanimated": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-2.2.0.tgz",
|
||||
"integrity": "sha512-lOJDd+5w1gY6DHGXG2jD1dsjzQmXQ2699HUc3IztvI2WP4zUT+UAA+zSG+5JiBS5DUnTL8YhhkmUQmr1KNGO5w==",
|
||||
"version": "2.3.0-alpha.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-2.3.0-alpha.2.tgz",
|
||||
"integrity": "sha512-SpzW1rPMjpy7dMEKo30873pmgj0cgczBgUHvrOKKCCPJbaQXR6w6pOGrTW5M6BQtM8zpIPPwSJN+p3G9W49aiA==",
|
||||
"dependencies": {
|
||||
"@babel/plugin-transform-object-assign": "^7.10.4",
|
||||
"fbjs": "^3.0.0",
|
||||
"invariant": "^2.2.4",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"mockdate": "^3.0.2",
|
||||
"string-hash-64": "^1.0.3"
|
||||
},
|
||||
|
|
@ -26607,6 +26754,18 @@
|
|||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-screens": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.6.0.tgz",
|
||||
"integrity": "sha512-emQmSu+B6cOIjJH2OIgpuxd9zCD6xz7/oo5GCetyjsM5qR3sMnVgOxqtK99xPu9XJH/8k7MplXbtJgtk/PHXwA==",
|
||||
"dependencies": {
|
||||
"warn-once": "^0.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native-share": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-6.5.0.tgz",
|
||||
|
|
@ -29567,6 +29726,14 @@
|
|||
"resolved": "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz",
|
||||
"integrity": "sha1-bIOv82kvphJW4M0ZfgXp3hV2kaY="
|
||||
},
|
||||
"node_modules/split-on-first": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
|
||||
"integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/split-string": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
|
||||
|
|
@ -29883,6 +30050,14 @@
|
|||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/strict-uri-encode": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
|
||||
"integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
|
|
@ -31616,6 +31791,11 @@
|
|||
"makeerror": "1.0.x"
|
||||
}
|
||||
},
|
||||
"node_modules/warn-once": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/warn-once/-/warn-once-0.1.0.tgz",
|
||||
"integrity": "sha512-recZTSvuaH/On5ZU5ywq66y99lImWqzP93+AiUo9LUwG8gXHW+LJjhOd6REJHm7qb0niYqrEQJvbHSQfuJtTqA=="
|
||||
},
|
||||
"node_modules/watchpack": {
|
||||
"version": "1.7.5",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz",
|
||||
|
|
@ -36306,6 +36486,16 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@react-native-community/art": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-community/art/-/art-1.2.0.tgz",
|
||||
"integrity": "sha512-a+ZcRGl/BzLa89yi33Mbn5SHavsEXqKUMdbfLf3U8MDLElndPqUetoJyGkv63+BcPO49UMWiQRP1YUz6/zfJ+A==",
|
||||
"requires": {
|
||||
"art": "^0.10.3",
|
||||
"invariant": "^2.2.4",
|
||||
"prop-types": "^15.7.2"
|
||||
}
|
||||
},
|
||||
"@react-native-community/async-storage": {
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-community/async-storage/-/async-storage-1.12.1.tgz",
|
||||
|
|
@ -37194,6 +37384,66 @@
|
|||
"resolved": "https://registry.npmjs.org/@react-native/polyfills/-/polyfills-1.0.0.tgz",
|
||||
"integrity": "sha512-0jbp4RxjYopTsIdLl+/Fy2TiwVYHy4mgeu07DG4b/LyM0OS/+lPP5c9sbnt/AMlnF6qz2JRZpPpGw1eMNS6A4w=="
|
||||
},
|
||||
"@react-navigation/bottom-tabs": {
|
||||
"version": "6.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/bottom-tabs/-/bottom-tabs-6.0.5.tgz",
|
||||
"integrity": "sha512-GytjJUzacHhe3C24HFrPl881Donrw2m+3JBNqMJALxMRjSA8yY72+l16bZR9YFsrywSHVSbjxIfzqtGb8rIVJg==",
|
||||
"requires": {
|
||||
"@react-navigation/elements": "^1.1.0",
|
||||
"color": "^3.1.3",
|
||||
"warn-once": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"@react-navigation/core": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/core/-/core-6.0.1.tgz",
|
||||
"integrity": "sha512-mVdvBDYdz8uzLQHokmVdX/xC4rS7NIkD1FN/yaGdovVzYApAhM+UGd3w1zskjyCSyXaVHHOwV59ZGVew+84xfQ==",
|
||||
"requires": {
|
||||
"@react-navigation/routers": "^6.0.1",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"nanoid": "^3.1.23",
|
||||
"query-string": "^7.0.0",
|
||||
"react-is": "^16.13.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@react-navigation/elements": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.1.0.tgz",
|
||||
"integrity": "sha512-jZncciZPGuoP6B6f+Wpf6MYSSYy86B2HJDbFTCtT5xZV0w6V9GgCeqvSTOEAxifZrmKl8uDxsr0GrIxgQE8NxA==",
|
||||
"requires": {}
|
||||
},
|
||||
"@react-navigation/native": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-6.0.2.tgz",
|
||||
"integrity": "sha512-HDqEwgvQ4Cu16vz8jQ55lfyNK9CGbECI1wM9cPOcUa+gkOQEDZ/95VFfFjGGflXZs3ybPvGXlMC4ZAyh1CcO6w==",
|
||||
"requires": {
|
||||
"@react-navigation/core": "^6.0.1",
|
||||
"escape-string-regexp": "^4.0.0",
|
||||
"nanoid": "^3.1.23"
|
||||
},
|
||||
"dependencies": {
|
||||
"escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@react-navigation/routers": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-6.0.1.tgz",
|
||||
"integrity": "sha512-5ctB49rmtTRQuTSBVgqMsEzBUjPP2ByUzBjNivA7jmvk+PDCl4oZsiR8KAm/twhxe215GYThfi2vUWXKAg6EEQ==",
|
||||
"requires": {
|
||||
"nanoid": "^3.1.23"
|
||||
}
|
||||
},
|
||||
"@rudderstack/rudder-sdk-react-native": {
|
||||
"version": "1.0.12",
|
||||
"resolved": "https://registry.npmjs.org/@rudderstack/rudder-sdk-react-native/-/rudder-sdk-react-native-1.0.12.tgz",
|
||||
|
|
@ -39539,6 +39789,11 @@
|
|||
"resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
|
||||
"integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug=="
|
||||
},
|
||||
"art": {
|
||||
"version": "0.10.3",
|
||||
"resolved": "https://registry.npmjs.org/art/-/art-0.10.3.tgz",
|
||||
"integrity": "sha512-HXwbdofRTiJT6qZX/FnchtldzJjS3vkLJxQilc3Xj+ma2MXjY4UAyQ0ls1XZYVnDvVIBiFZbC6QsvtW86TD6tQ=="
|
||||
},
|
||||
"asap": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
|
||||
|
|
@ -43730,6 +43985,11 @@
|
|||
"to-regex-range": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"filter-obj": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-1.1.0.tgz",
|
||||
"integrity": "sha1-mzERErxsYSehbgFsbF1/GeCAXFs="
|
||||
},
|
||||
"finalhandler": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
|
||||
|
|
@ -51443,9 +51703,7 @@
|
|||
"nanoid": {
|
||||
"version": "3.1.23",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz",
|
||||
"integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==",
|
||||
"dev": true,
|
||||
"peer": true
|
||||
"integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw=="
|
||||
},
|
||||
"nanomatch": {
|
||||
"version": "1.2.13",
|
||||
|
|
@ -53018,6 +53276,17 @@
|
|||
"escape-goat": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"query-string": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-7.0.1.tgz",
|
||||
"integrity": "sha512-uIw3iRvHnk9to1blJCG3BTc+Ro56CBowJXKmNNAm3RulvPBzWLRqKSiiDk+IplJhsydwtuNMHi8UGQFcCLVfkA==",
|
||||
"requires": {
|
||||
"decode-uri-component": "^0.2.0",
|
||||
"filter-obj": "^1.1.0",
|
||||
"split-on-first": "^1.0.0",
|
||||
"strict-uri-encode": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"querystring": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
|
||||
|
|
@ -53390,6 +53659,15 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"react-native-neomorph-shadows": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-neomorph-shadows/-/react-native-neomorph-shadows-1.1.2.tgz",
|
||||
"integrity": "sha512-HJ7bBEwuze6TNxz/+1RvaHrrHHYMEZ0itE3hPgGxvst7Jz47K9TnEDiFskjTXMaTxXOCqzPDa9UmUfQK2K15tA==",
|
||||
"requires": {
|
||||
"@react-native-community/art": "^1.2.0",
|
||||
"prop-types": "^15.7.2"
|
||||
}
|
||||
},
|
||||
"react-native-notifications": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/react-native-notifications/-/react-native-notifications-4.1.1.tgz",
|
||||
|
|
@ -53411,12 +53689,13 @@
|
|||
}
|
||||
},
|
||||
"react-native-reanimated": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-2.2.0.tgz",
|
||||
"integrity": "sha512-lOJDd+5w1gY6DHGXG2jD1dsjzQmXQ2699HUc3IztvI2WP4zUT+UAA+zSG+5JiBS5DUnTL8YhhkmUQmr1KNGO5w==",
|
||||
"version": "2.3.0-alpha.2",
|
||||
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-2.3.0-alpha.2.tgz",
|
||||
"integrity": "sha512-SpzW1rPMjpy7dMEKo30873pmgj0cgczBgUHvrOKKCCPJbaQXR6w6pOGrTW5M6BQtM8zpIPPwSJN+p3G9W49aiA==",
|
||||
"requires": {
|
||||
"@babel/plugin-transform-object-assign": "^7.10.4",
|
||||
"fbjs": "^3.0.0",
|
||||
"invariant": "^2.2.4",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"mockdate": "^3.0.2",
|
||||
"string-hash-64": "^1.0.3"
|
||||
}
|
||||
|
|
@ -53437,6 +53716,14 @@
|
|||
"integrity": "sha512-k2Nty4PwSnrg9HwrYeeE+EYqViYJoOFwEy9LxL5RIRfoqxAq/uQXNGwpUg2/u4gnKpBbEPa9eRh15KKMe/VHkA==",
|
||||
"requires": {}
|
||||
},
|
||||
"react-native-screens": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-3.6.0.tgz",
|
||||
"integrity": "sha512-emQmSu+B6cOIjJH2OIgpuxd9zCD6xz7/oo5GCetyjsM5qR3sMnVgOxqtK99xPu9XJH/8k7MplXbtJgtk/PHXwA==",
|
||||
"requires": {
|
||||
"warn-once": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"react-native-share": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/react-native-share/-/react-native-share-6.5.0.tgz",
|
||||
|
|
@ -55862,6 +56149,11 @@
|
|||
"resolved": "https://registry.npmjs.org/split-ca/-/split-ca-1.0.1.tgz",
|
||||
"integrity": "sha1-bIOv82kvphJW4M0ZfgXp3hV2kaY="
|
||||
},
|
||||
"split-on-first": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
|
||||
"integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw=="
|
||||
},
|
||||
"split-string": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
|
||||
|
|
@ -56132,6 +56424,11 @@
|
|||
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
|
||||
"integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
|
||||
},
|
||||
"strict-uri-encode": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
|
||||
"integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="
|
||||
},
|
||||
"string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
|
|
@ -57477,6 +57774,11 @@
|
|||
"makeerror": "1.0.x"
|
||||
}
|
||||
},
|
||||
"warn-once": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/warn-once/-/warn-once-0.1.0.tgz",
|
||||
"integrity": "sha512-recZTSvuaH/On5ZU5ywq66y99lImWqzP93+AiUo9LUwG8gXHW+LJjhOd6REJHm7qb0niYqrEQJvbHSQfuJtTqA=="
|
||||
},
|
||||
"watchpack": {
|
||||
"version": "1.7.5",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz",
|
||||
|
|
|
|||
|
|
@ -19,12 +19,15 @@
|
|||
"@mattermost/react-native-paste-input": "0.1.4",
|
||||
"@nozbe/watermelondb": "0.23.0",
|
||||
"@nozbe/with-observables": "1.4.0",
|
||||
"@react-native-community/art": "1.2.0",
|
||||
"@react-native-community/async-storage": "1.12.1",
|
||||
"@react-native-community/cameraroll": "4.0.4",
|
||||
"@react-native-community/clipboard": "1.5.1",
|
||||
"@react-native-community/masked-view": "0.1.11",
|
||||
"@react-native-community/netinfo": "6.0.0",
|
||||
"@react-native-cookies/cookies": "6.0.8",
|
||||
"@react-navigation/bottom-tabs": "6.0.5",
|
||||
"@react-navigation/native": "6.0.2",
|
||||
"@rudderstack/rudder-sdk-react-native": "1.0.12",
|
||||
"@sentry/react-native": "2.6.1",
|
||||
"@types/mime-db": "1.43.1",
|
||||
|
|
@ -60,11 +63,13 @@
|
|||
"react-native-linear-gradient": "2.5.6",
|
||||
"react-native-localize": "2.1.1",
|
||||
"react-native-navigation": "7.18.1",
|
||||
"react-native-neomorph-shadows": "1.1.2",
|
||||
"react-native-notifications": "4.1.1",
|
||||
"react-native-permissions": "3.0.5",
|
||||
"react-native-reanimated": "2.2.0",
|
||||
"react-native-reanimated": "2.3.0-alpha.2",
|
||||
"react-native-redash": "16.1.1",
|
||||
"react-native-safe-area-context": "3.2.0",
|
||||
"react-native-screens": "3.6.0",
|
||||
"react-native-share": "6.5.0",
|
||||
"react-native-slider": "0.11.0",
|
||||
"react-native-svg": "12.1.1",
|
||||
|
|
|
|||
7
types/api/preferences.d.ts
vendored
7
types/api/preferences.d.ts
vendored
|
|
@ -1,7 +1,12 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
type ThemeKey = 'denim' | 'sapphire' | 'quartz' | 'indigo' | 'onyx';
|
||||
|
||||
type ThemeType = 'Denim' | 'Sapphire' | 'Quartz' | 'Indigo' | 'Onyx' | 'custom';
|
||||
|
||||
type Theme = {
|
||||
[key: string]: string | undefined;
|
||||
type?: string;
|
||||
sidebarBg: string;
|
||||
sidebarText: string;
|
||||
|
|
@ -15,7 +20,6 @@ type Theme = {
|
|||
awayIndicator: string;
|
||||
dndIndicator: string;
|
||||
mentionBg: string;
|
||||
mentionBj: string;
|
||||
mentionColor: string;
|
||||
centerChannelBg: string;
|
||||
centerChannelColor: string;
|
||||
|
|
@ -27,5 +31,4 @@ type Theme = {
|
|||
mentionHighlightBg: string;
|
||||
mentionHighlightLink: string;
|
||||
codeTheme: string;
|
||||
[key: string]: any;
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue