Merge pull request #6768 from pvev/MM-35065-add-onboarding-screens

Mm 35065 add onboarding screens
This commit is contained in:
Pablo Andrés Vélez Vidal 2022-11-29 16:27:56 +01:00 committed by GitHub
commit 9e010ff5a3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 2116 additions and 22 deletions

View file

@ -3,6 +3,7 @@
import {GLOBAL_IDENTIFIERS} from '@constants/database';
import DatabaseManager from '@database/manager';
import {logError} from '@utils/log';
export const storeGlobal = async (id: string, value: unknown, prepareRecordsOnly = false) => {
try {
@ -12,6 +13,7 @@ export const storeGlobal = async (id: string, value: unknown, prepareRecordsOnly
prepareRecordsOnly,
});
} catch (error) {
logError('storeGlobal', error);
return {error};
}
};
@ -24,6 +26,10 @@ export const storeMultiServerTutorial = async (prepareRecordsOnly = false) => {
return storeGlobal(GLOBAL_IDENTIFIERS.MULTI_SERVER_TUTORIAL, 'true', prepareRecordsOnly);
};
export const storeOnboardingViewedValue = async (value = true) => {
return storeGlobal(GLOBAL_IDENTIFIERS.ONBOARDING, value, false);
};
export const storeProfileLongPressTutorial = async (prepareRecordsOnly = false) => {
return storeGlobal(GLOBAL_IDENTIFIERS.PROFILE_LONG_PRESS_TUTORIAL, 'true', prepareRecordsOnly);
};

View file

@ -78,6 +78,7 @@ export const GLOBAL_IDENTIFIERS = {
LAST_ASK_FOR_REVIEW: 'lastAskForReview',
MULTI_SERVER_TUTORIAL: 'multiServerTutorial',
PROFILE_LONG_PRESS_TUTORIAL: 'profileLongPressTutorial',
ONBOARDING: 'onboarding',
};
export enum OperationType {

View file

@ -33,6 +33,7 @@ export const LATEX = 'Latex';
export const LOGIN = 'Login';
export const MENTIONS = 'Mentions';
export const MFA = 'MFA';
export const ONBOARDING = 'Onboarding';
export const PERMALINK = 'Permalink';
export const PINNED_MESSAGES = 'PinnedMessages';
export const POST_OPTIONS = 'PostOptions';
@ -97,6 +98,7 @@ export default {
LOGIN,
MENTIONS,
MFA,
ONBOARDING,
PERMALINK,
PINNED_MESSAGES,
POST_OPTIONS,

View file

@ -6,13 +6,15 @@ import {Alert, DeviceEventEmitter, Linking, Platform} from 'react-native';
import {Notifications} from 'react-native-notifications';
import {appEntry, pushNotificationEntry, upgradeEntry} from '@actions/remote/entry';
import LocalConfig from '@assets/config.json';
import {Screens, DeepLink, Events, Launch, PushNotification} from '@constants';
import DatabaseManager from '@database/manager';
import {getActiveServerUrl, getServerCredentials, removeServerCredentials} from '@init/credentials';
import {getOnboardingViewed} from '@queries/app/global';
import {getThemeForCurrentTeam} from '@queries/servers/preference';
import {getCurrentUserId} from '@queries/servers/system';
import {queryMyTeams} from '@queries/servers/team';
import {goToScreen, resetToHome, resetToSelectServer, resetToTeams} from '@screens/navigation';
import {goToScreen, resetToHome, resetToSelectServer, resetToTeams, resetToOnboarding} from '@screens/navigation';
import EphemeralStore from '@store/ephemeral_store';
import {logInfo} from '@utils/log';
import {convertToNotificationData} from '@utils/notification';
@ -58,6 +60,13 @@ const launchAppFromNotification = async (notification: NotificationWithData, col
launchApp(props);
};
/**
*
* @param props set of properties used to determine how to launch the app depending on the containing values
* @param resetNavigation used when loading the add_server screen and remove all the navigation stack
* @returns a redirection to a screen, either onboarding, add_server, login or home depending on the scenario
*/
const launchApp = async (props: LaunchProps, resetNavigation = true) => {
let serverUrl: string | undefined;
switch (props?.launchType) {
@ -126,6 +135,13 @@ const launchApp = async (props: LaunchProps, resetNavigation = true) => {
}
}
const onboardingViewed = LocalConfig.ShowOnboarding && await getOnboardingViewed();
// if the config value is set and the onboarding has not been seeing yet, show the onboarding
if (LocalConfig.ShowOnboarding && !onboardingViewed) {
return resetToOnboarding(props);
}
return launchToServer(props, resetNavigation);
};

View file

@ -5,6 +5,7 @@ import CookieManager, {Cookie} from '@react-native-cookies/cookies';
import {AppState, AppStateStatus, DeviceEventEmitter, Platform} from 'react-native';
import FastImage from 'react-native-fast-image';
import {storeOnboardingViewedValue} from '@actions/app/global';
import {cancelSessionNotification, logout, scheduleSessionNotification} from '@actions/remote/session';
import {Events, Launch} from '@constants';
import DatabaseManager from '@database/manager';
@ -15,7 +16,7 @@ import PushNotifications from '@init/push_notifications';
import * as analytics from '@managers/analytics';
import NetworkManager from '@managers/network_manager';
import WebsocketManager from '@managers/websocket_manager';
import {queryServerName} from '@queries/app/servers';
import {queryAllServers, queryServerName} from '@queries/app/servers';
import {getCurrentUser} from '@queries/servers/user';
import {getThemeFromState} from '@screens/navigation';
import EphemeralStore from '@store/ephemeral_store';
@ -177,6 +178,14 @@ class SessionManager {
}
}
// set the onboardingViewed value to false so the launch will show the onboarding screen after all servers were removed
if (DatabaseManager.appDatabase) {
const servers = await queryAllServers(DatabaseManager.appDatabase.database);
if (!servers.length) {
await storeOnboardingViewedValue(false);
}
}
relaunchApp({launchType, serverUrl, displayName}, true);
}
};

View file

@ -41,6 +41,16 @@ export const observeMultiServerTutorial = () => {
);
};
export const getOnboardingViewed = async (): Promise<boolean> => {
try {
const {database} = DatabaseManager.getAppDatabaseAndOperator();
const onboardingVal = await database.get<GlobalModel>(GLOBAL).find(GLOBAL_IDENTIFIERS.ONBOARDING);
return onboardingVal?.value ?? false;
} catch {
return false;
}
};
export const observeProfileLongPresTutorial = () => {
const query = queryGlobalValue(GLOBAL_IDENTIFIERS.PROFILE_LONG_PRESS_TUTORIAL);
if (!query) {

View file

@ -249,6 +249,8 @@ Navigation.setLazyComponentRegistrator((screenName) => {
export function registerScreens() {
const homeScreen = require('@screens/home').default;
const serverScreen = require('@screens/server').default;
const onboardingScreen = require('@screens/onboarding').default;
Navigation.registerComponent(Screens.ONBOARDING, () => withGestures(withIntl(withManagedConfig(onboardingScreen)), undefined));
Navigation.registerComponent(Screens.SERVER, () => withGestures(withIntl(withManagedConfig(serverScreen)), undefined));
Navigation.registerComponent(Screens.HOME, () => withGestures(withSafeAreaInsets(withServerDatabase(withManagedConfig(homeScreen))), undefined));
}

View file

@ -124,6 +124,19 @@ export const bottomSheetModalOptions = (theme: Theme, closeButtonId?: string): O
// This locks phones to portrait for all screens while keeps
// all orientations available for Tablets.
Navigation.setDefaultOptions({
animations: {
setRoot: {
enter: {
waitForRender: true,
enabled: true,
alpha: {
from: 0,
to: 1,
duration: 300,
},
},
},
},
layout: {
orientation: Device.IS_TABLET ? undefined : ['portrait'],
},
@ -148,7 +161,7 @@ Appearance.addChangeListener(() => {
const theme = getThemeFromState();
const screens = NavigationStore.getAllNavigationComponents();
if (screens.includes(Screens.SERVER)) {
if (screens.includes(Screens.SERVER) || screens.includes(Screens.ONBOARDING)) {
for (const screen of screens) {
if (appearanceControlledScreens.has(screen)) {
Navigation.updateProps(screen, {theme});
@ -286,6 +299,54 @@ export function resetToSelectServer(passProps: LaunchProps) {
});
}
export function resetToOnboarding(passProps: LaunchProps) {
const theme = getDefaultThemeByAppearance();
const isDark = tinyColor(theme.sidebarBg).isDark();
StatusBar.setBarStyle(isDark ? 'light-content' : 'dark-content');
NavigationStore.clearNavigationComponents();
const children = [{
component: {
id: Screens.ONBOARDING,
name: Screens.ONBOARDING,
passProps: {
...passProps,
theme,
},
options: {
layout: {
backgroundColor: theme.centerChannelBg,
componentBackgroundColor: theme.centerChannelBg,
},
statusBar: {
visible: true,
backgroundColor: theme.sidebarBg,
},
topBar: {
backButton: {
color: theme.sidebarHeaderTextColor,
title: '',
},
background: {
color: theme.sidebarBg,
},
visible: false,
height: 0,
},
},
},
}];
return Navigation.setRoot({
root: {
stack: {
children,
},
},
});
}
export function resetToTeams() {
const theme = getThemeFromState();
const isDark = tinyColor(theme.sidebarBg).isDark();

View file

@ -0,0 +1,164 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {Pressable, useWindowDimensions, View} from 'react-native';
import Animated, {Extrapolate, interpolate, useAnimatedStyle} from 'react-native-reanimated';
import CompassIcon from '@components/compass_icon';
import FormattedText from '@components/formatted_text';
import {ONBOARDING_CONTENT_MAX_WIDTH} from '@screens/onboarding/slide';
import {buttonBackgroundStyle, buttonTextStyle} from '@utils/buttonStyles';
import {makeStyleSheetFromTheme} from '@utils/theme';
type Props = {
theme: Theme;
lastSlideIndex: number;
nextSlideHandler: () => void;
signInHandler: () => void;
scrollX: Animated.SharedValue<number>;
};
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
button: {
marginTop: 5,
},
rowIcon: {
color: theme.buttonColor,
fontSize: 12,
marginLeft: 5,
marginTop: 4.5,
},
nextButtonText: {
flexDirection: 'row',
position: 'absolute',
},
signInButtonText: {
flexDirection: 'row',
},
footerButtonsContainer: {
flexDirection: 'column',
height: 120,
marginTop: 25,
marginBottom: 15,
width: '100%',
alignItems: 'center',
},
}));
const AnimatedButton = Animated.createAnimatedComponent(Pressable);
const BUTTON_SIZE = 100;
const FooterButtons = ({
theme,
nextSlideHandler,
signInHandler,
lastSlideIndex,
scrollX,
}: Props) => {
const {width} = useWindowDimensions();
const buttonWidth = Math.min(width * 0.8, ONBOARDING_CONTENT_MAX_WIDTH);
const styles = getStyleSheet(theme);
// keep in mind penultimate and ultimate slides to run buttons text/opacity/size animations
const penultimateSlide = lastSlideIndex - 1;
const inputRange = [(penultimateSlide * width), lastSlideIndex * width];
// the next button must resize in the last slide to be the 80% wide of the screen with animation
const resizeStyle = useAnimatedStyle(() => {
const interpolatedWidth = interpolate(
scrollX.value,
inputRange,
[BUTTON_SIZE, buttonWidth],
Extrapolate.CLAMP,
);
return {width: interpolatedWidth};
});
// use for the opacity of the button text in the penultimate and last slide
const opacityNextTextStyle = useAnimatedStyle(() => {
const interpolatedScale = interpolate(
scrollX.value,
[penultimateSlide * width, ((penultimateSlide * width) + (width / 2))],
[1, 0], // from last to penultimate it must fade out (from 1 to 0), once it starts getting the penultimate range it must fade in again (from 0 to 1)
Extrapolate.CLAMP,
);
return {opacity: interpolatedScale};
});
const opacitySignInTextStyle = useAnimatedStyle(() => {
const interpolatedScale = interpolate(
scrollX.value,
[lastSlideIndex * width, ((penultimateSlide * width) + (width / 2))],
[1, 0], // from last to penultimate it must fade out (from 1 to 0), once it starts getting the penultimate range it must fade in again (from 0 to 1)
Extrapolate.CLAMP,
);
return {opacity: interpolatedScale};
});
// the sign in button should fade out until dissappear in the last slide
const opacitySignInButton = useAnimatedStyle(() => {
const interpolatedScale = interpolate(
scrollX.value,
inputRange,
[1, 0],
Extrapolate.CLAMP,
);
return {opacity: interpolatedScale};
});
const nextButtonText = (
<Animated.View style={[styles.nextButtonText, opacityNextTextStyle]}>
<FormattedText
id='mobile.onboarding.next'
defaultMessage='Next'
style={buttonTextStyle(theme, 'lg', 'primary', 'default')}
/>
<CompassIcon
name='arrow-forward-ios'
style={styles.rowIcon}
/>
</Animated.View>
);
const signInButtonText = (
<Animated.View style={[styles.signInButtonText, opacitySignInTextStyle]}>
<FormattedText
id='mobile.onboarding.sign_in_to_get_started'
defaultMessage='Sign in to get started'
style={buttonTextStyle(theme, 'lg', 'primary', 'default')}
/>
</Animated.View>
);
return (
<View style={styles.footerButtonsContainer}>
<AnimatedButton
testID='mobile.onboaring.next'
onPress={nextSlideHandler}
style={[styles.button, buttonBackgroundStyle(theme, 'lg', 'primary', 'default'), resizeStyle]}
>
{nextButtonText}
{signInButtonText}
</AnimatedButton>
<AnimatedButton
testID='mobile.onboaring.sign_in'
onPress={signInHandler}
style={[styles.button, buttonBackgroundStyle(theme, 'lg', 'link', 'default'), opacitySignInButton]}
>
<FormattedText
id='mobile.onboarding.sign_in'
defaultMessage='Sign in'
style={buttonTextStyle(theme, 'lg', 'primary', 'inverted')}
/>
</AnimatedButton>
</View>
);
};
export default FooterButtons;

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,149 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import * as React from 'react';
import {StyleProp, ViewStyle} from 'react-native';
import Svg, {
G,
Path,
Ellipse,
} from 'react-native-svg';
type Props = {
theme: Theme;
styles: StyleProp<ViewStyle>;
};
const ChatSvg = ({theme, styles}: Props) => {
return (
<Svg
width={263}
height={212}
viewBox='0 0 263 212'
fill='none'
style={styles}
>
<G clipPath='url(#clip0_1023_92018)'>
<Path
d='M176.396 29c-3.441 5.745-14.534 1.149-16.633 12.065 4.083 0 19.145 2.08 19.145 2.08L176.396 29z'
fill='#4A2407'
/>
<Path
d='M159.269 86.21c-4.852 8.63-44.21 25.658-34.827 69.563 6.642 31.104 21.796 43.514 18.021 48.707-2.799 3.792-5.001 8.411 1.652 2.953 8.03-6.561 10.887-2.206 5.679-18.017-4.967-15.052-9.338-55.153 15.474-69.378 24.813-14.225 32.912-21.338 20.649-38.803-4.486-6.412-26.648 4.975-26.648 4.975z'
fill='#AD831F'
/>
<Path
d='M139.516 193.726c.826-.23 7.846-2.459 10.507-3.585 4.887 14.937 1.974 10.835-5.907 17.293-6.654 5.457-4.451.839-1.652-2.953 1.514-2.114-.046-5.447-2.948-10.755z'
fill='#1C58D9'
/>
<Path
d='M187.752 42.18l.631-12.766 1.709-4.71c-1.056-4.689-3.774-6.895-5.3-7.309-3.441-.85-5.391-.988-7.273.483-1.032.884-2.627 4.93-3.315 8.1-.367 1.712-1.147 3.08 0 4.137a19.554 19.554 0 002.489 1.666l.184 8.043 10.875 2.356z'
fill='#AD831F'
/>
<Path
d='M176.396 21.118a14.637 14.637 0 00-3.109 2.045c-.39 1.149 2.627 2.298 2.627 2.298l.482-4.343z'
fill='#AD831F'
/>
<Path
d='M180.365 32.838a8.292 8.292 0 01-3.625-1.023c-.402-.253.734.747 1.147.977a3.7 3.7 0 001.789.666c.482 0 1.17-.586.689-.62z'
fill='#8B6918'
/>
<Path
d='M202.768 90.703c2.294 31.805 3.085 74.469 31.718 81.581 28.632 7.113 27.531 3.597 27.531 14.26s-2.214 9.088-3.522 2.298c-1.675-8.779-32.957 6.894-54.179-10.617-21.222-17.512-30.181-51.362-33.416-86.086-2.271-24.59 31.868-1.436 31.868-1.436z'
fill='#AD831F'
/>
<Path
d='M250.271 175.824c12.389 2.631 11.758 2.551 11.758 10.674 0 10.663-2.214 9.089-3.522 2.298-.585-3.045-4.738-3.148-10.794-2.711a49.014 49.014 0 002.558-10.261z'
fill='#1C58D9'
/>
<Path
d='M104.781 44.834c.665-1.15 6.217-1.333 12.744 3.976 6.527 5.308 17.138 11.915 28.942-2.448 10.588-12.903 17.632-8.043 28.357-7.618 3.809.483 19.18 2.448 23.103 2.804 5.736-.104 15.521 2.631 22.289-13.168 2.593-6.055 5.277-14.765 9.005-20.683 2.558-4.044 5.07-6.515 7.445-7.503 1.755-.724.78.667-.574 2.677-.906 1.368.104 1.207-.401 2.942-.298 1.011-.436 1.609-.769 2.482a20.454 20.454 0 00-.711 2.401c-.149.62-.298 1.276-.424 1.976l-.104.483c-1.376 7.56-2.122 18.649-3.154 23.107-3.602 15.34-11.471 24.394-25.845 27.577a257.068 257.068 0 01-.447 7.17c-2.581 36.195 1.089 26.428-22.404 26.428s-29.745 14.11-26.212-6.124c1.664-9.48 1.147-20.5 2.971-31.737-3.579 2.23-9.36 6.802-15.165 8.239-18.067 4.435-34.735-19.178-34.895-20.683-.253-2.321-4.405-1.114-3.751-2.298z'
fill='#AD831F'
/>
<Path
d='M153.533 64.874c2.398-1.506 3.384-4.263 5.059-5.298a127.57 127.57 0 00-1.342 12.938c-.195 3.068-.344 6.09-.551 9.02a95.15 95.15 0 01-1.078 9.79c-3.533 20.223 2.719 6.136 26.212 6.102 20.568 0 20.316 7.503 21.669-14.938v-.15c.069-.964.127-1.976.195-3.044.149-2.46.322-5.205.54-8.296.183-2.62.344-4.999.447-7.17 6.298-1.402 11.356-1.861 15.36-5.573-2.065-5.94-4.715-13.696-8.672-18.626-4.233 2.448-8.546 2.034-11.919 1.92h-1.526l-2.03-.208c-1.48-.16-3.442-.39-5.518-.643-1.147 5.883-10.255 5.01-13.261 2.953A12.146 12.146 0 01173 38.629a81.189 81.189 0 01-3.671-.424c-1.181-.161-2.214-.31-3.28-.437-6.459-.782-12.148-.46-19.582 8.594-.459.563-.918 1.07-1.365 1.563a149.59 149.59 0 008.431 16.949z'
fill={theme.centerChannelBg}
/>
<Path
d='M153.533 64.874c2.398-1.506 3.384-4.263 5.059-5.298a127.57 127.57 0 00-1.342 12.938c-.195 3.068-.344 6.09-.551 9.02a95.15 95.15 0 01-1.078 9.79c-3.533 20.223 2.719 6.136 26.212 6.102 20.568 0 20.316 7.503 21.669-14.938v-.15c.069-.964.127-1.976.195-3.044.149-2.46.322-5.205.54-8.296.183-2.62.344-4.999.447-7.17 6.298-1.402 11.356-1.861 15.36-5.573-2.065-5.94-4.715-13.696-8.672-18.626-4.233 2.448-8.546 2.034-11.919 1.92h-1.526l-2.03-.208c-1.48-.16-3.442-.39-5.518-.643-1.147 5.883-10.255 5.01-13.261 2.953A12.146 12.146 0 01173 38.629a81.189 81.189 0 01-3.671-.424c-1.181-.161-2.214-.31-3.28-.437-6.459-.782-12.148-.46-19.582 8.594-.459.563-.918 1.07-1.365 1.563a149.59 149.59 0 008.431 16.949z'
fill={theme.centerChannelBg}
/>
<Path
d='M153.533 64.874c2.398-1.506 3.384-4.263 5.059-5.298a127.57 127.57 0 00-1.342 12.938c-.195 3.068-.344 6.09-.551 9.02a95.15 95.15 0 01-1.078 9.79c-3.533 20.223 2.719 6.136 26.212 6.102 20.568 0 20.316 7.503 21.669-14.938v-.15c.069-.964.127-1.976.195-3.044.149-2.46.322-5.205.54-8.296.183-2.62.344-4.999.447-7.17 6.298-1.402 11.356-1.861 15.36-5.573-2.065-5.94-4.715-13.696-8.672-18.626-4.233 2.448-8.546 2.034-11.919 1.92h-1.526l-2.03-.208c-1.48-.16-3.442-.39-5.518-.643-1.147 5.883-10.255 5.01-13.261 2.953A12.146 12.146 0 01173 38.629a81.189 81.189 0 01-3.671-.424c-1.181-.161-2.214-.31-3.28-.437-6.459-.782-12.148-.46-19.582 8.594-.459.563-.918 1.07-1.365 1.563a149.59 149.59 0 008.431 16.949z'
fill={theme.centerChannelColor}
fillOpacity={0.08}
/>
<Path
d='M136.946 107.295a105.804 105.804 0 0015.222 17.178l.493.437a195.036 195.036 0 003.442 2.987c.462-.547.973-1.05 1.525-1.505l.505-.425c1.858-1.563 4.52-3.447 7.17-5.32 3.728-2.574 7.41-4.952 8.695-5.745.94 5.194 2.053 10.341 3.361 15.225l.172.654c.218.77.424 1.54.642 2.298a110.202 110.202 0 0025.673-3.573l.643-.184 1.319-.402c.15-.048.303-.086.459-.115-.161-1-.31-2.103-.459-3.298 0-.229 0-.448-.081-.678-1.583-13.65-2.409-38.251-2.225-42.296v-.149a15.072 15.072 0 01-1.411-1.31c-.191-.2-.386-.406-.585-.62-4.279-4.803-6.39-11.778-7.617-16.03.425-9.399 1.296-14.385 5.564-22.83-.539 0-2.719-.15-3.556-.242a61.53 61.53 0 00-5.002 19.821c-8.03-1.46-16.06-2.758-24.09-3.999a112.698 112.698 0 012.467-18.959c-1.147-.15-2.214-.31-3.281-.436a95.116 95.116 0 00-2.18 21.463c-.459 1.15-1.365 4.597-2.03 5.86a74.988 74.988 0 01-4.589 7.435c-.195 3.068-.344 6.09-.55 9.02-.207 2.93-.471 5.745-.884 8.491-3.98 3.585-10.415 8.273-16.541 14.696-.149.161-.31.322-.459.494-.574.644-1.193 1.333-1.812 2.057z'
fill={theme.buttonBg}
/>
<Path
d='M187.856 88.416a4.124 4.124 0 002.535-.643c.998-.735 1.377-2.126 1.652-4.125.688-4.884.355-5.297-1.457-7.595-.585-.736-1.319-1.655-2.225-3a23.7 23.7 0 01-1.985-3.446c-1.147-2.436-1.617-2.988-7.468-4.125-9.464-1.839-10.198-1.287-12.951 2.367-.505.666-1.067 1.413-1.778 2.298-4.21 4.986-4.244 5.619-4.37 7.963 0 .632-.081 1.413-.218 2.447-.207 1.47-.218 2.447.332 3.171.861 1.15 2.845 1.368 7.617 1.954 1.962.241 4.405.54 7.399.988 2.294.345 4.302.666 6.046.954 2.269.42 4.565.685 6.871.793zm-9.017-22.67v.322c5.736 1.149 5.943 1.574 6.998 3.768a25.23 25.23 0 002.03 3.585 35.16 35.16 0 002.295 3.045c1.755 2.207 1.973 2.494 1.33 7.09-.298 2.16-.677 3.16-1.388 3.689-1.239.907-3.797.482-8.913-.368-1.744-.288-3.717-.61-6.057-.954-3.005-.448-5.449-.747-7.41-.988-4.314-.529-6.482-.804-7.17-1.7-.413-.54-.39-1.391-.206-2.678.149-1.057.183-1.861.218-2.505.126-2.172.149-2.746 4.221-7.572a41.556 41.556 0 001.79-2.298c2.523-3.332 2.982-3.941 12.308-2.126l-.046-.31z'
fill='#2D3039'
/>
<Path
d='M184.299 68.825c.239.499.515.98.826 1.437.229.356-.333.689-.574.333-.31-.458-.587-.938-.826-1.436-.183-.38.402-.713.574-.334zM186.112 72.135c.39.609.78 1.149 1.204 1.77.241.344-.321.677-.573.333-.413-.575-.815-1.15-1.147-1.77-.322-.356.298-.69.516-.333zM188.979 76.041c.3.408.63.792.987 1.15.31.287-.161.757-.47.459-.36-.355-.69-.74-.987-1.15-.252-.333.207-.804.47-.459zM190.287 80.408c0-.425.631-.425.654 0 .034.44.034.881 0 1.321 0 .425-.688.425-.654 0 .035-.44.035-.882 0-1.321zM189.702 83.958c.069-.425.711-.24.631.173-.08.414-.184 1.149-.287 1.712-.103.563-.7.241-.631-.184l.287-1.7zM184.54 85.05c.838.23 1.694.392 2.558.482.413 0 .425.701 0 .655a16.798 16.798 0 01-2.73-.494.332.332 0 01-.075-.605.331.331 0 01.247-.038zM178.128 84.314c.838.054 1.673.154 2.5.3.425.068.241.7-.172.631a22.534 22.534 0 00-2.294-.264c-.459-.034-.459-.666-.034-.666zM171.853 83.59l2.294.288c.413 0 .413.712 0 .655l-2.294-.276c-.413-.058-.424-.724 0-.666zM165.636 82.947l1.927.219c.413 0 .424.712 0 .666l-1.927-.23c-.413-.046-.425-.7 0-.655zM162.332 81.442l.711.655c.309.287-.149.758-.471.471l-.711-.666c-.344-.288.115-.747.471-.46zM161.505 77.593c0-.413.712-.425.666 0-.08.763-.118 1.53-.115 2.298a.33.33 0 01-.327.272.331.331 0 01-.327-.272c-.013-.767.022-1.535.103-2.298zM162.928 74.123l.666-.988c.229-.357.803 0 .562.333l-.654.988c-.241.356-.803.023-.574-.333zM179.229 67.079c.771.038 1.538.134 2.294.287.413.092.241.724-.172.644a11.92 11.92 0 00-2.111-.265c-.436-.034-.436-.666-.011-.666zM174.216 66.182c.731.035 1.459.115 2.18.242.424.069.241.7-.172.632a14.664 14.664 0 00-2.008-.207c-.413-.023-.413-.678 0-.667zM169.892 65.93a8.449 8.449 0 011.525-.116.332.332 0 010 .656 7.396 7.396 0 00-1.342.103c-.424.058-.596-.575-.183-.643zM166.92 69.159l.769-1.15c.24-.344.814 0 .562.334l-.769 1.15c-.264.344-.837.022-.562-.334zM165.016 72.493l.665-.885c.252-.333.826 0 .574.334l-.666.884c-.252.356-.826.035-.573-.333z'
fill='#2D3039'
/>
<Path
d='M192.238 58.358c2.512.69 2.914.173 2.592 3.62-.321 3.447 0 3.113-3.246 2.505-2.294-.449-1.824-1.15-1.434-3.31.39-2.16.688-3.194 2.088-2.815zM164.752 54.715c2.581.357 2.914-.218 3.052 3.24.137 3.46-.562 3.207-2.891 2.908-2.329-.299-1.95-.85-1.858-3.08.091-2.229.263-3.263 1.697-3.068z'
fill='#FFBC1F'
/>
<Path
d='M185.962 32.608s-2.776 1.655-1.525 6.584c-3.373-5.033 1.055-11.938 1.055-11.938a1.156 1.156 0 00.941.49 1.147 1.147 0 00.94-.49c3.35-3.448.952-4.597 0-4.195-1.194.4-2.429.662-3.682.782-1.95.322-3.854-2.838-3.854-2.838l.493 1.436a5.545 5.545 0 01-2.81-4.596c1.778-5.688 12.733-6.699 16.816 1.884 4.084 8.584 0 23.395 11.931 21.671-23.7 10.514-20.305-8.79-20.305-8.79z'
fill='#4A2407'
/>
<Path
d='M139.275 104.721c6.779 9.595 18.847 21.223 18.847 21.223M177.359 130.103c11.827.449 28.449-4.596 28.449-4.596'
stroke='#1E325C'
strokeWidth={0.58}
strokeMiterlimit={10}
/>
<Path
d='M66.08 57.903h53.515a7.478 7.478 0 015.288 2.165 7.459 7.459 0 012.205 5.262v33.94a7.439 7.439 0 01-2.205 5.262 7.473 7.473 0 01-5.288 2.165h-7.898v12.705L99.85 106.697H66.1a7.477 7.477 0 01-5.289-2.165 7.443 7.443 0 01-2.205-5.262V65.33a7.445 7.445 0 012.199-5.255 7.476 7.476 0 015.276-2.172z'
fill='#1C58D9'
/>
<Path
d='M99.85 106.697H66.1a7.477 7.477 0 01-5.288-2.165 7.441 7.441 0 01-2.205-5.262V78.665s2.356 19.054 2.78 20.731c.423 1.677 1.263 4.187 5.244 4.603 3.98.416 33.22 2.698 33.22 2.698z'
fill='#000'
fillOpacity={0.16}
/>
<Path
d='M111.116 77.448a4.817 4.817 0 00-4.454 2.97 4.8 4.8 0 001.045 5.243 4.823 4.823 0 005.254 1.043 4.824 4.824 0 002.163-1.772 4.802 4.802 0 00-.598-6.077 4.806 4.806 0 00-3.41-1.407zM92.837 77.448a4.828 4.828 0 00-4.454 2.97 4.801 4.801 0 001.045 5.243 4.823 4.823 0 005.253 1.043 4.804 4.804 0 001.566-7.848 4.816 4.816 0 00-3.41-1.408zM74.578 77.448a4.814 4.814 0 00-4.458 2.965 4.802 4.802 0 001.04 5.245 4.824 4.824 0 008.233-3.399 4.796 4.796 0 00-1.408-3.401 4.815 4.815 0 00-3.407-1.41z'
fill={theme.centerChannelBg}
/>
<Path
d='M121.534 72.114a15.117 15.117 0 00-2.704-5.28 15.159 15.159 0 00-4.53-3.837.523.523 0 01.215-.99c3.374-.201 10.185.517 8.049 10.057a.525.525 0 01-.495.429.531.531 0 01-.535-.379z'
fill='#fff'
fillOpacity={0.16}
/>
<Path
d='M70.946 13.983H8.512a8.763 8.763 0 00-3.337.648 8.716 8.716 0 00-2.833 1.867 8.652 8.652 0 00-1.898 2.801 8.607 8.607 0 00-.674 3.31v39.42a8.607 8.607 0 00.674 3.31 8.653 8.653 0 001.898 2.802 8.717 8.717 0 002.833 1.867 8.765 8.765 0 003.337.648h9.214v14.756l13.82-14.756h39.378a8.764 8.764 0 003.336-.648 8.717 8.717 0 002.833-1.867 8.653 8.653 0 001.898-2.802 8.608 8.608 0 00.675-3.31V22.61a8.627 8.627 0 00-2.565-6.104 8.742 8.742 0 00-6.155-2.522z'
fill='#FFBC1F'
/>
<Path
d='M31.547 70.656h39.377a8.763 8.763 0 003.336-.648 8.718 8.718 0 002.833-1.867 8.651 8.651 0 001.898-2.802 8.606 8.606 0 00.675-3.31V38.098s-2.75 22.13-3.243 24.078c-.494 1.948-1.475 4.862-6.118 5.345-4.644.484-38.758 3.135-38.758 3.135z'
fill='#CC8F00'
/>
<Path
d='M18.404 36.684c1.112 0 2.2.328 3.124.942a5.595 5.595 0 012.072 2.508 5.554 5.554 0 01-1.22 6.089 5.659 5.659 0 01-6.13 1.211 5.617 5.617 0 01-2.523-2.058 5.562 5.562 0 01.697-7.057 5.62 5.62 0 013.98-1.635zM39.73 36.684c1.112 0 2.2.328 3.124.942a5.596 5.596 0 012.072 2.508 5.553 5.553 0 01.32 3.228 5.576 5.576 0 01-1.54 2.86 5.658 5.658 0 01-6.13 1.211 5.617 5.617 0 01-2.523-2.057 5.561 5.561 0 01.698-7.057 5.62 5.62 0 013.979-1.635zM61.03 36.684a5.651 5.651 0 013.128.938 5.596 5.596 0 012.074 2.507 5.554 5.554 0 01-1.214 6.091 5.658 5.658 0 01-6.13 1.215 5.617 5.617 0 01-2.526-2.058 5.561 5.561 0 01.695-7.056 5.62 5.62 0 013.974-1.637z'
fill={theme.centerChannelBg}
/>
<Path
d='M6.249 30.49a17.533 17.533 0 013.155-6.133A17.662 17.662 0 0114.69 19.9a.61.61 0 00.322-.67.607.607 0 00-.573-.48c-3.936-.234-11.882.601-9.39 11.68a.614.614 0 00.577.498.623.623 0 00.624-.439z'
fill='#FFD470'
/>
<Ellipse
cx={185.757}
cy={209.889}
rx={44.4842}
ry={2.25131}
fill='#000'
fillOpacity={0.12}
/>
</G>
</Svg>
);
};
export default ChatSvg;

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,261 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {StyleProp, ViewStyle} from 'react-native';
import Svg, {
Ellipse,
Path,
Mask,
G,
} from 'react-native-svg';
type Props = {
theme: Theme;
styles: StyleProp<ViewStyle>;
}
const TeamCommunicationSvg = ({theme, styles}: Props) => {
return (
<Svg
width={253}
height={208}
viewBox='0 0 253 208'
fill='none'
style={styles}
>
<Ellipse
cx={67.493}
cy={90.6649}
rx={66.4115}
ry={66.2887}
fill={theme.centerChannelBg}
/>
<Path
d='M67.493 157.454c36.953 0 66.911-29.902 66.911-66.79 0-36.886-29.958-66.788-66.911-66.788S.582 53.778.582 90.665s29.958 66.789 66.911 66.789z'
stroke={theme.centerChannelColor}
strokeOpacity={0.16}
/>
<Ellipse
cx={67.493}
cy={90.6649}
rx={66.4115}
ry={66.2887}
fill={theme.centerChannelColor}
fillOpacity={0.16}
/>
<Mask
id='a'
maskUnits='userSpaceOnUse'
>
<Ellipse
cx={67.493}
cy={90.6649}
rx={66.4115}
ry={66.2887}
fill='#fff'
/>
</Mask>
<G mask='url(#a)'>
<Path
d='M39.256 77.027h18.43l.646-10.269c1.062-.315 3.468-2.393 4.15-2.673 2.864-1.147 5.923-17.056 5.011-19.363-1.163-2.58-9.269 1.354-13.325.064-3.734-1.19-8.63 3.762-8.853 9.402l-6.06 22.84z'
fill='#FFBC1F'
/>
<Ellipse
cx={63.9032}
cy={51.2501}
rx={1.07694}
ry={1.07495}
fill='#6F370B'
/>
<Path
d='M87.955 155.09c-7.675 2.795-15.96 4.315-24.605 4.315-4.954 0-9.793-.502-14.467-1.455-15.364-3.139-28.948-11.158-39.05-22.366-.179-5.382-.193-11.689.03-19.063 1.342-43.75 4.12-41.615 42.488-41.901 43.38-.323 37.45 17.937 38.01 33.309.358 9.789-.92 32.263-2.406 47.161z'
fill={theme.centerChannelBg}
/>
<Path
d='M45.76 84.853c2.721 1.01 9.98.538 11.48-1.634 1.034-1.505 2.018-3.053 3.03-4.572.812-1.225 1.608-2.45 2.384-3.698-3.08-.243-6.498-.358-10.303-.33-5.083.036-9.527.036-13.44.1 3.748 4.143 1.644 8.206 6.85 10.134zM90.353 98.304c-1.343.093-2.664.301-3.906.51-6.39 1.081-2.9 3.152-2.663 26.701.122 11.903 2.204 18.69.947 30.579 0 .028-.014.05-.014.079a64.146 64.146 0 003.245-1.09c1.486-14.899 2.764-37.372 2.405-47.161-.115-3.147.043-6.414 0-9.625l-.014.007zM73.502 147.351c-.265 7.374-.983 6.163-7.086 2.2-4.703-3.053-12.622 4.464-24.18 6.7a71.825 71.825 0 01-25.819-14.246c-4.975-12.126-6.002-28.859-6.002-38.362 0-.953 22.566 1.226 22.566 1.226-.13 17.249 1.6 37.379 15.902 34.835 14.302-2.537 24.892.273 24.62 7.647z'
fill='#FFBC1F'
/>
<Path
d='M131.722 109.985c-9.42 28.694-36.473 49.42-68.372 49.42-4.954 0-9.793-.502-14.467-1.455v-6.342h22.193s10.776-40.906 10.676-41.623h49.97z'
fill='#484D5B'
/>
<Path
d='M105.129 109.985H81.752c.043.323-2.154 8.951-4.574 18.267 9.341-6.048 18.646-12.154 27.951-18.267zM92.75 127.199c6.319-3.927 12.651-7.833 19.013-11.688 2.864-1.735 5.636-3.662 8.443-5.526h-9.851c-11.394 7.489-22.788 14.971-34.24 22.374-.552 2.135-1.105 4.249-1.629 6.256 6.088-3.805 12.17-7.625 18.265-11.416z'
fill='#6C7389'
/>
<Path
d='M70.408 38.981c-1.493-1.97-3.77-.516-6.146.165-5.018 2.129-11.401-1.505-16.04 1.355-3.553 2.185-4.17 6.994-4.422 11.157-.107 1.828.194 4.236 1.996 4.601.618.122 1.271-.057 1.881.086 1.723.395 1.932 2.716 1.917 4.48-.021 3.045.517 6.212 2.32 8.67 1.794 2.459 5.082 4.007 7.99 3.082 3.453-1.096 5.09-4.952 6.167-8.399.632-2.042 2.248-5.504.352-6.5-2.032-1.075-7.438 1.563-10.03-.193-1.759-1.197-1.658-3.777-1.364-5.884.201-1.447.452-2.995 1.472-4.042 1.637-1.69 4.365-1.325 6.72-1.246 2.147.078 4.437-.244 6.103-1.606 1.666-1.361 2.39-4.013 1.091-5.718l-.007-.008z'
fill='#6F370B'
/>
<Path
d='M66.258 48.778a266.15 266.15 0 012.886 8.75c-.28 1.627-5.463-.043-5.463-.043l2.577-8.707zM52.538 48.778s-3.77-1.068-3.647 2.48c.122 3.547 4.25 2.773 4.25 2.773l-.596-5.253h-.007z'
fill='#FFBC1F'
/>
</G>
<Path
d='M148.526 18.32H98.48a6.962 6.962 0 00-4.946 2.036 7.014 7.014 0 00-2.062 4.95v31.927a7.035 7.035 0 002.062 4.95 6.984 6.984 0 004.946 2.036h7.386v11.952l11.078-11.952h31.564a6.965 6.965 0 004.946-2.036 7.025 7.025 0 002.062-4.95V25.306a7.024 7.024 0 00-2.056-4.944 6.972 6.972 0 00-4.934-2.043z'
fill='#FFBC1F'
/>
<Path
d='M116.944 64.22h31.564a6.965 6.965 0 004.946-2.037 7.024 7.024 0 002.062-4.95V37.85s-2.204 17.924-2.6 19.501c-.396 1.578-1.182 3.938-4.904 4.33-3.723.391-31.068 2.538-31.068 2.538z'
fill='#CC8F00'
/>
<Path
d='M106.409 36.705c.892 0 1.763.266 2.505.763a4.522 4.522 0 011.66 2.03 4.543 4.543 0 01-.977 4.933 4.492 4.492 0 01-4.913.98 4.533 4.533 0 01-2.783-4.18 4.535 4.535 0 011.318-3.202 4.51 4.51 0 013.19-1.324zM123.503 36.705c.892 0 1.764.266 2.505.763a4.535 4.535 0 01.683 6.963 4.502 4.502 0 01-4.913.98 4.533 4.533 0 01-2.783-4.18 4.517 4.517 0 011.319-3.202 4.506 4.506 0 013.189-1.324zM140.579 36.705a4.495 4.495 0 012.506.76 4.522 4.522 0 011.663 2.03 4.545 4.545 0 01-.973 4.934 4.49 4.49 0 01-4.914.984 4.517 4.517 0 01-2.025-1.668 4.543 4.543 0 01.557-5.714 4.503 4.503 0 013.186-1.326z'
fill={theme.centerChannelBg}
/>
<Path
d='M96.666 31.688a14.254 14.254 0 012.53-4.967 14.194 14.194 0 014.235-3.61.494.494 0 00-.2-.93c-3.156-.19-9.525.486-7.528 9.46a.5.5 0 00.463.403.495.495 0 00.5-.356z'
fill='#FFD470'
/>
<Ellipse
cx={198.383}
cy={150.952}
rx={53.6174}
ry={53.5182}
fill={theme.centerChannelBg}
/>
<Path
d='M198.383 204.97c29.887 0 54.117-24.184 54.117-54.018 0-29.835-24.23-54.019-54.117-54.019-29.888 0-54.118 24.184-54.118 54.019 0 29.834 24.23 54.018 54.118 54.018z'
stroke={theme.centerChannelColor}
strokeOpacity={0.16}
/>
<Ellipse
cx={198.383}
cy={150.952}
rx={53.6174}
ry={53.5182}
fill={theme.centerChannelColor}
fillOpacity={0.16}
/>
<Mask
id='b'
maskUnits='userSpaceOnUse'
>
<Ellipse
cx={198.383}
cy={150.952}
rx={53.6174}
ry={53.5182}
fill='#fff'
/>
</Mask>
<G mask='url(#b)'>
<Path
d='M210.875 125.784c-3.074 0-5.757.121-8.091.386-17.64 1.983-10.847 10.028-13.268 32.765-2.738 25.751-8.427 41.419 18.763 44.087 27.19 2.668 31.165-13.17 33.438-42.502 2.273-29.326-3.975-34.736-30.842-34.736z'
fill={theme.centerChannelBg}
/>
<Path
d='M197.734 185.922s.014 6.945-2.067 14.057c-.499 1.715-1.118 3.436-1.9 5.069h-26.26a165.66 165.66 0 003.003-39.886c-.033-.861-1.387-.861-1.347 0a164.613 164.613 0 01-3.03 39.886h-22.207c.532-.497.128-44.256 13.296-60.075a18.558 18.558 0 013.623-3.368c9.174-6.481 15.741-3.94 21.324 4.417 1.192 1.781 2.337 3.825 3.455 6.111 2.425 4.961 4.715 11.025 7.025 17.876a584.942 584.942 0 013.22 9.93c.269.867.545 1.741.822 2.628.343 1.11.693 2.226 1.043 3.355z'
fill='#82889C'
/>
<Path
d='M177.555 205.048h-11.423a164.563 164.563 0 003.031-39.886c-.04-.861 1.038-.807 1.347 0 4.857 12.666 9.652 26.77 7.045 39.886z'
fill='#3F4350'
/>
<Path
d='M238.752 185.102c.324 7.435.768 14.877-.094 19.946H168.16c3.085-6.487 8.917-10.346 17.013-15.301 3.442-2.097 7.294-4.403 11.517-7.18.344-.235.694-.464 1.044-.699 0 0 .277-.128.782-.356 5.839-2.636 42.573-18.495 40.634.343v.013c-.115 1.123-.445 2.192-.398 3.234z'
fill='#A4A9B7'
/>
<Path
d='M238.746 204.463c.734-5.048.316-12.202 0-19.361-.047-1.042.283-2.111.397-3.234v-.013c1.933-18.777-34.552-3.08-40.573-.37 10.002 12.787 24.119 21.607 40.169 22.978h.007z'
fill='#3F4350'
/>
<Path
d='M202.936 126.362c-11.177.942-39.797-1.45-44.092 11.581-3.912 11.851 8.658 10.218 12.071 18.797 3.407 8.579 3.602 15.66 6.82 8.023 3.219-7.637-.592-17.361-2.194-21.555-1.596-4.195 12.482 8.579 21.261 4.005 8.779-4.574 6.134-20.851 6.134-20.851z'
fill={theme.centerChannelBg}
/>
<Path
d='M160.343 135.237c-.639.857-1.157 1.788-1.5 2.834-3.907 11.801 8.648 10.175 12.058 18.717 3.403 8.542 3.598 15.593 6.812 7.989 3.215-7.604-.592-17.287-2.192-21.463-2.045-7.274-11.251-8.907-15.178-8.077z'
fill='#A37200'
/>
<Path
d='M228.89 144.895c-.1-.845-.976-.772-.916.087 1.639 22.147-8.434 28.823-8.434 28.823 9.874-5.585 10.703-17.733 9.35-28.91zM190.175 137.256c-.447 2.401-1.53 5.579-1.333 8.096.072.907.604 1.732.689 2.666.151 1.562.355 5.033.276 6.616-.039.872 1.326-5.743.407-8.491-.873-2.612.387-5.756.906-8.519.157-.852-.788-1.213-.945-.361v-.007z'
fill={theme.centerChannelColor}
fillOpacity={0.64}
/>
<Path
d='M189.745 173.227h-6.484c-.804 0-1.532-.473-1.827-1.199l-4.643-11.221c-.522-1.252.432-2.623 1.827-2.623h6.484c.803 0 1.532.473 1.827 1.198l4.643 11.221c.522 1.252-.433 2.624-1.827 2.624z'
fill={theme.centerChannelColor}
/>
<Path
d='M222.202 126.369c20.056 1.498 25.161 7.51 25.161 30.04 0 35.031-20.789 38.181-36.466 31.108-15.677-7.067-24.335-13.415-27.29-18.957-2.384-4.467 2.902 0 8.98 1.216 1.525.302 2.909 1.135 4.319 1.518 31.939 8.679 36.164-4.305 34.337-19.614-1.827-15.309-9.035-25.318-9.035-25.318l-.006.007z'
fill='#A37200'
/>
<Path
d='M222.249 126.362s5.42 8.321 7.251 23.638c1.254 10.527-5 22-10.068 23.677-.134 5.435-1.381 10.829-3.95 15.545 14.841 4.494 31.881-1.075 31.881-32.817 0-22.532-5.097-28.545-25.121-30.043h.007z'
fill={theme.centerChannelBg}
/>
<Path
d='M154.275 202.801h-33.368a2.26 2.26 0 01-1.386-.663 2.309 2.309 0 01-.655-1.404v-43.883a2.3 2.3 0 01.658-1.421 2.268 2.268 0 011.404-.666h24.745l10.715 10.727v35.222c.006.264-.041.527-.138.773a1.926 1.926 0 01-.429.653c-.418.404-.968.64-1.546.662z'
fill='#000'
fillOpacity={0.2}
/>
</G>
<Path
d='M202.252 119.598l5.813 10.236c4.396-.459 7.519-2.686 11.935-2.834-2.46-3.054-9.134-13.895-9.809-14.751-1.26-1.605.178-5.893-.627-7.269-2.889-5.036-10.555-2.117-12.307-1.692-1.696.405-4.961 2.414-4.961 2.414 1.172 3.756 3.687 9.736 7.081 14.112.572.742 1.69.351 2.875-.216z'
fill='#A37200'
/>
<Path
d='M194.845 109.005c-.876 3.699-1.389 6.342-1.389 6.342.349 1.216 4.057.21 4.057.21l-2.668-6.552z'
fill='#A37200'
/>
<Path
d='M202.5 119.5c.874-.481 1.389-.931 2.069-1.693.305-.348.569.104.451.555-.09.347-.569.873-1.201 1.183-.402.2-1.909.281-1.319-.045z'
fill='#6F370B'
/>
<Path
d='M215.661 106.608c-.892-.782-2.043-1.403-2.472-2.498-.381-.982-.075-2.084-.279-3.112-.354-1.77-2.247-2.96-4.086-2.986-1.839-.026-6.872 1.884-8.826 1.937-1.955.047-3.923-.12-5.85.207-1.928.327-3.869 1.242-4.829 2.912-.96 1.67-.531 4.147 1.219 4.989 1.471.708 3.242.1 4.631-.748 1.39-.848 2.67-1.957 4.257-2.351 1.586-.394 3.63.307 3.929 1.883.17.902-.265 1.797-.402 2.705-.136.908.252 2.077 1.179 2.164 1.055.1 1.886-1.276 2.908-1.008.905.24.967 1.435 1.151 2.33.429 2.118 2.69 3.66 4.882 3.48 2.193-.18 4.1-1.943 4.591-4.054.49-2.11-.368-4.415-2.009-5.857l.006.007z'
fill='#4A2407'
/>
<Path
d='M238.359 120.558c.744-1.516.724-3.045.724-4.703 0-.521.101-.968.27-1.367-.068-.44-.115-.887-.135-1.333-.088-1.848.419-3.871 1.886-4.995.643-.494 1.427-.792 1.981-1.374 1.089-1.157.906-3.011.393-4.513-1.015-2.978-3.084-5.604-5.782-7.221-2.697-1.618-6.017-2.2-9.087-1.516-1.684.372-3.266 1.103-4.936 1.536-1.67.433-3.53.535-5.037-.305-1.616-.893-6.559-2.422-8.405-2.504-16.532-.717-19.839 9.137-20.785 10.456-1.069 1.34 16.18-3.214 18.033-2.199 1.061-1.55.216 12.012 1.731 14.279 1.075 1.611 4.956 6.876 12.008 9.441 4.172.467 8.392.704 12.394-.44 1.373-.393 2.759-1.069 4.037-1.942.25-.42.494-.853.717-1.3h-.007z'
fill='#4A2407'
/>
<Path
d='M211.404 133.302c4.77-.1 8.432-3.064 10.454-7.062-3.218-.329-6.88-.457-11.045-.457-3.077 0-5.745.128-8.083.39 1.532 3.938 3.675 7.237 8.667 7.129h.007z'
fill='#A37200'
/>
<Path
d='M183.147 140.425a250.153 250.153 0 00-1.199 13.716c-.062 1.08 1.791.93 1.854-.134.267-4.431.655-8.853 1.166-13.268.118-1.067-1.694-1.39-1.821-.314zM198.094 147.776a72.644 72.644 0 01-7.577 8.737c-.765.75.344 2.01 1.109 1.259a76.024 76.024 0 007.851-9.07c.641-.869-.75-1.794-1.383-.926zM207.294 164.374c-3.906-.147-7.821-.303-11.727-.451-.899-.031-.769 1.652.123 1.693 3.906.148 7.821.304 11.727.451.899.032.769-1.652-.123-1.693z'
fill='#FFBC1F'
/>
<Path
d='M198.4 118.479a6.115 6.115 0 001.969-.933c.244-.179-.012-.574-.26-.396-.605.44-1.29.752-2.014.923l.305.406z'
fill='#4A2407'
/>
<Ellipse
cx={197.351}
cy={110.709}
rx={1.00127}
ry={0.666278}
transform='rotate(-13.871 197.351 110.709)'
fill='#4A2407'
/>
<G clipPath='url(#clip0_418_7357)'>
<Path
d='M149.275 195.801h-33.368a2.26 2.26 0 01-1.386-.663 2.311 2.311 0 01-.655-1.404v-43.883a2.298 2.298 0 012.062-2.088h24.745l10.715 10.728v35.222c.006.264-.041.527-.138.772a1.92 1.92 0 01-.429.654 2.359 2.359 0 01-1.546.662z'
fill='#E8E9ED'
/>
<Path
d='M136.061 155.075H118.53a.688.688 0 01-.5-.259.724.724 0 01-.153-.547c0-.475.219-.713.653-.713h17.531c.439 0 .658.238.658.713a.714.714 0 01-.658.806zm-2.72 5.127c.199 0 .39-.08.531-.223a.766.766 0 000-1.074.745.745 0 00-.531-.223h-14.796a.765.765 0 00-.667.76.765.765 0 00.667.76h14.796zm11.623 5.219a.753.753 0 00.812-.757.778.778 0 00-.242-.559.741.741 0 00-.57-.198H118.53a.753.753 0 00-.464.256.77.77 0 00.464 1.258h26.434zm-1.684 5.131c.432 0 .682-.253.75-.759a.826.826 0 00-.235-.522.807.807 0 00-.515-.238h-24.75a.688.688 0 00-.5.259.729.729 0 00-.153.547c0 .475.219.713.653.713h24.75zm-9.939 5.219c.199 0 .39-.08.531-.222a.768.768 0 000-1.074.745.745 0 00-.531-.223h-14.796a.766.766 0 00-.667.76.765.765 0 00.667.759h14.796zm11.623 5.127c.439 0 .689-.254.75-.76a.817.817 0 00-.234-.522.804.804 0 00-.516-.238H118.53a.704.704 0 00-.633.517.723.723 0 00-.02.289c0 .476.219.714.653.714h26.434zm0 5.224a.81.81 0 00.515-.239.826.826 0 00.235-.521.816.816 0 00-.233-.523.795.795 0 00-.517-.236H118.53a.75.75 0 00-.477.251.77.77 0 000 1.017c.123.14.293.229.477.251h26.434zm0 5.126c.439 0 .689-.253.75-.76a.7.7 0 00-.232-.498.695.695 0 00-.518-.168H118.53c-.434 0-.653.238-.653.713s.219.713.653.713h26.434z'
fill='#989DAE'
/>
<Path
d='M140.653 147.763l10.587 10.728h-8.342a2.219 2.219 0 01-1.592-.615 2.162 2.162 0 01-.659-1.664l.006-8.449z'
fill='#BABEC9'
/>
</G>
<Path
fillRule='evenodd'
clipRule='evenodd'
d='M161.915 54.431a1.5 1.5 0 011.626-1.362c4.754.418 12.243 3.2 19.554 7.49 6.326 3.711 12.707 8.66 17.203 14.432l2.18-9.876a1.501 1.501 0 012.93.647l-2.91 13.182a1.501 1.501 0 01-1.789 1.141l-13.182-2.91a1.5 1.5 0 11.647-2.93l9.339 2.063c-4.155-5.145-9.993-9.675-15.936-13.162-7.141-4.189-14.182-6.726-18.3-7.089a1.5 1.5 0 01-1.362-1.626zM102.839 185.763a1.5 1.5 0 01-1.439 1.559c-4.086.162-10.71-1.381-17.324-4.201-5.578-2.377-11.338-5.741-15.723-9.971l-.909 10.107a1.5 1.5 0 01-2.987-.268l1.209-13.446a1.5 1.5 0 011.628-1.36l13.446 1.209a1.501 1.501 0 01-.269 2.988l-9.463-.851c3.957 3.641 9.106 6.642 14.244 8.833 6.433 2.742 12.581 4.099 16.029 3.962a1.5 1.5 0 011.558 1.439z'
fill={theme.centerChannelColor}
fillOpacity={0.32}
/>
</Svg>
);
};
export default TeamCommunicationSvg;

View file

@ -0,0 +1,163 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useCallback, useEffect, useRef} from 'react';
import {
View,
useWindowDimensions,
SafeAreaView,
ScrollView,
StyleSheet,
Platform,
NativeSyntheticEvent,
NativeScrollEvent,
} from 'react-native';
import {Navigation} from 'react-native-navigation';
import Animated, {useAnimatedStyle, useDerivedValue, useSharedValue, withTiming} from 'react-native-reanimated';
import {storeOnboardingViewedValue} from '@actions/app/global';
import {Screens} from '@constants';
import Background from '@screens/background';
import {goToScreen, loginAnimationOptions} from '@screens/navigation';
import FooterButtons from './footer_buttons';
import Paginator from './paginator';
import SlideItem from './slide';
import useSlidesData from './slides_data';
import type {LaunchProps} from '@typings/launch';
interface OnboardingProps extends LaunchProps {
theme: Theme;
}
const styles = StyleSheet.create({
onBoardingContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
verticalAlign: 'top',
},
scrollContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
const AnimatedSafeArea = Animated.createAnimatedComponent(SafeAreaView);
const Onboarding = ({
theme,
}: OnboardingProps) => {
const {width} = useWindowDimensions();
const {slidesData} = useSlidesData();
const LAST_SLIDE_INDEX = slidesData.length - 1;
const slidesRef = useRef<ScrollView>(null);
const scrollX = useSharedValue(0);
// used to smothly animate the whole onboarding screen during the appear event scenario (from server screen back to onboarding screen)
const translateX = useSharedValue(width);
const currentIndex = useDerivedValue(() => Math.round(scrollX.value / width));
const moveToSlide = useCallback((slideIndexToMove: number) => {
slidesRef.current?.scrollTo({
x: (slideIndexToMove * width),
animated: true,
});
}, [width]);
const signInHandler = useCallback(() => {
// mark the onboarding as already viewed
storeOnboardingViewedValue();
goToScreen(Screens.SERVER, '', {animated: true, theme}, loginAnimationOptions());
}, []);
const nextSlide = useCallback(() => {
const nextSlideIndex = currentIndex.value + 1;
if (slidesRef.current && currentIndex.value < LAST_SLIDE_INDEX) {
moveToSlide(nextSlideIndex);
} else if (slidesRef.current && currentIndex.value === LAST_SLIDE_INDEX) {
signInHandler();
}
}, [currentIndex, moveToSlide, signInHandler]);
const scrollHandler = useCallback((event: NativeSyntheticEvent<NativeScrollEvent>) => {
scrollX.value = event.nativeEvent.contentOffset.x;
}, []);
useEffect(() => {
const listener = {
componentDidAppear: () => {
translateX.value = 0;
},
componentDidDisappear: () => {
translateX.value = -width;
},
};
const unsubscribe = Navigation.events().registerComponentListener(listener, Screens.ONBOARDING);
return () => unsubscribe.remove();
}, [width]);
const transform = useAnimatedStyle(() => {
const duration = Platform.OS === 'android' ? 250 : 350;
return {
transform: [{translateX: withTiming(translateX.value, {duration})}],
};
}, []);
return (
<View
style={styles.onBoardingContainer}
testID='onboarding.screen'
>
<Background theme={theme}/>
<AnimatedSafeArea
style={[styles.scrollContainer, transform]}
key={'onboarding_content'}
>
<ScrollView
scrollEventThrottle={16}
horizontal={true}
showsHorizontalScrollIndicator={false}
pagingEnabled={true}
bounces={false}
onScroll={scrollHandler}
ref={slidesRef}
>
{slidesData.map((item, index) => {
return (
<SlideItem
item={item}
theme={theme}
scrollX={scrollX}
index={index}
key={`key-${index.toString()}`}
lastSlideIndex={LAST_SLIDE_INDEX}
/>
);
})}
</ScrollView>
<Paginator
dataLength={slidesData.length}
theme={theme}
scrollX={scrollX}
moveToSlide={moveToSlide}
/>
<FooterButtons
theme={theme}
nextSlideHandler={nextSlide}
signInHandler={signInHandler}
scrollX={scrollX}
lastSlideIndex={LAST_SLIDE_INDEX}
/>
</AnimatedSafeArea>
</View>
);
};
export default Onboarding;

View file

@ -0,0 +1,129 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {View, useWindowDimensions, TouchableOpacity} from 'react-native';
import Animated, {interpolate, useAnimatedStyle} from 'react-native-reanimated';
import {makeStyleSheetFromTheme} from '@utils/theme';
type Props = {
dataLength: number;
theme: Theme;
scrollX: Animated.SharedValue<number>;
moveToSlide: (slideIndexToMove: number) => void;
};
const DOT_SIZE = 16;
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
const commonStyle = {
height: DOT_SIZE / 2,
borderRadius: 5,
backgroundColor: theme.buttonBg,
marginHorizontal: DOT_SIZE / 2,
width: DOT_SIZE / 2,
opacity: 0.25,
};
return {
dot: {
...commonStyle,
},
fixedDot: {
...commonStyle,
position: 'absolute',
},
outerDot: {
height: DOT_SIZE,
borderRadius: DOT_SIZE / 2,
backgroundColor: theme.buttonBg,
marginHorizontal: 4,
marginTop: -4,
position: 'absolute',
width: DOT_SIZE,
opacity: 0.15,
},
paginatorContainer: {
flexDirection: 'row',
height: 15,
justifyContent: 'space-between',
width: 120,
},
};
});
const Paginator = ({
theme,
dataLength,
scrollX,
moveToSlide,
}: Props) => {
const styles = getStyleSheet(theme);
return (
<View style={styles.paginatorContainer}>
{[...Array(dataLength)].map((_, index: number) => {
return (
<Dot
key={`key-${index.toString()}`}
theme={theme}
moveToSlide={moveToSlide}
index={index}
scrollX={scrollX}
/>
);
})}
</View>
);
};
type DotProps = {
index: number;
scrollX: Animated.SharedValue<number>;
theme: Theme;
moveToSlide: (slideIndexToMove: number) => void;
};
// this has to be extracted as a component since the useAnimatedStyle hook cant be used inside a loop
const Dot = ({
index,
scrollX,
theme,
moveToSlide,
}: DotProps) => {
const {width} = useWindowDimensions();
const styles = getStyleSheet(theme);
const inputRange = [(index - 1) * width, index * width, (index + 1) * width];
const dotOpacity = useAnimatedStyle(() => {
const opacity = interpolate(
scrollX.value,
inputRange,
[0, 1, 0],
);
return {opacity};
});
const outerDotOpacity = useAnimatedStyle(() => {
const opacity = interpolate(
scrollX.value,
inputRange,
[0, 0.15, 0],
);
return {opacity};
});
return (
<TouchableOpacity
onPress={() => moveToSlide(index)}
hitSlop={{top: 8, left: 8, right: 8, bottom: 8}}
>
<Animated.View style={styles.fixedDot}/>
<Animated.View style={[styles.outerDot, outerDotOpacity]}/>
<Animated.View style={[styles.dot, dotOpacity]}/>
</TouchableOpacity>
);
};
export default Paginator;

View file

@ -0,0 +1,224 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useEffect, useMemo, useState} from 'react';
import {View, useWindowDimensions} from 'react-native';
import Animated, {Extrapolate, interpolate, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
import {typography} from '@utils/typography';
import type {OnboardingItem} from '@typings/screens/onboarding';
type Props = {
item: OnboardingItem;
theme: Theme;
scrollX: Animated.SharedValue<number>;
index: number;
lastSlideIndex: number;
};
export const ONBOARDING_CONTENT_MAX_WIDTH = 520;
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
image: {
justifyContent: 'center',
maxHeight: 180,
},
title: {
color: theme.centerChannelColor,
textAlign: 'center',
paddingHorizontal: 20,
maxWidth: ONBOARDING_CONTENT_MAX_WIDTH,
marginBottom: 12,
},
fontTitle: {
marginTop: 32,
...typography('Heading', 1000, 'SemiBold'),
},
fontFirstTitle: {
...typography('Heading', 1200, 'SemiBold'),
paddingTop: 48,
letterSpacing: -1,
},
widthLastSlide: {
paddingHorizontal: 50,
},
firstSlideInitialPosition: {
left: 200,
opacity: 0,
},
description: {
textAlign: 'center',
paddingHorizontal: 20,
color: changeOpacity(theme.centerChannelColor, 0.64),
...typography('Body', 200, 'Regular'),
maxWidth: ONBOARDING_CONTENT_MAX_WIDTH,
},
itemContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
}));
const FIRST_SLIDE = 0;
const SlideItem = ({theme, item, scrollX, index, lastSlideIndex}: Props) => {
const {width} = useWindowDimensions();
const styles = getStyleSheet(theme);
/**
* Code used to animate the first image load
*/
const [firstLoad, setFirstLoad] = useState(true);
const initialImagePosition = useSharedValue(width);
const initialTitlePosition = useSharedValue(width);
const initialDescriptionPosition = useSharedValue(width);
const initialElementsOpacity = useSharedValue(0);
useEffect(() => {
if (index === FIRST_SLIDE) {
initialImagePosition.value = withTiming(0, {duration: 600});
initialTitlePosition.value = withTiming(0, {duration: 800});
initialDescriptionPosition.value = withTiming(0, {duration: 1000});
initialElementsOpacity.value = withTiming(1, {duration: 1000});
setFirstLoad(false);
}
}, []);
const translateFirstImageOnLoad = useAnimatedStyle(() => {
return {
transform: [{
translateX: initialImagePosition.value,
}],
opacity: initialElementsOpacity.value,
};
});
const translateFirstTitleOnLoad = useAnimatedStyle(() => {
return {
transform: [{
translateX: initialTitlePosition.value,
}],
opacity: initialElementsOpacity.value,
};
});
const translateFirstDescriptionOnLoad = useAnimatedStyle(() => {
return {
transform: [{
translateX: initialDescriptionPosition.value,
}],
opacity: initialElementsOpacity.value,
};
});
// end of code for animating first image load
const inputRange = useMemo(() => [(index - 1) * width, index * width, (index + 1) * width], [width, index]);
const translateImage = useAnimatedStyle(() => {
const translateImageInterpolate = interpolate(
scrollX.value,
inputRange,
[width * 2, 0, -width * 2],
Extrapolate.CLAMP,
);
return {
transform: [{
translateX: translateImageInterpolate,
}],
};
});
const translateTitle = useAnimatedStyle(() => {
const translateTitleInterpolate = interpolate(
scrollX.value,
inputRange,
[width * 0.6, 0, -width * 0.6],
Extrapolate.CLAMP,
);
return {
transform: [{
translateX: translateTitleInterpolate,
}],
};
});
const translateDescription = useAnimatedStyle(() => {
const translateDescriptionInterpolate = interpolate(
scrollX.value,
inputRange,
[width * 0.2, 0, -width * 0.2],
Extrapolate.CLAMP,
);
return {
transform: [{
translateX: translateDescriptionInterpolate,
}],
};
});
const opacity = useAnimatedStyle(() => {
const opacityInterpolate = interpolate(
scrollX.value,
inputRange,
[0.2, 1, 0.2],
Extrapolate.CLAMP,
);
return {opacity: opacityInterpolate};
});
return (
<View style={[styles.itemContainer, {width}]}>
<Animated.View
style={[
styles.image,
translateImage,
opacity,
translateFirstImageOnLoad,
(index === FIRST_SLIDE && firstLoad ? styles.firstSlideInitialPosition : undefined),
]}
>
{item.image}
</Animated.View>
<View>
<Animated.Text
style={[
styles.title,
(index === FIRST_SLIDE ? styles.fontFirstTitle : styles.fontTitle),
(index === lastSlideIndex ? styles.widthLastSlide : undefined),
translateTitle,
opacity,
translateFirstTitleOnLoad,
(index === FIRST_SLIDE && firstLoad ? styles.firstSlideInitialPosition : undefined),
]}
>
{item.title}
</Animated.Text>
<Animated.Text
style={[
styles.description,
translateDescription,
opacity,
(index === FIRST_SLIDE && firstLoad ? styles.firstSlideInitialPosition : undefined),
(index === lastSlideIndex ? styles.widthLastSlide : undefined),
translateFirstDescriptionOnLoad,
]}
>
{item.description}
</Animated.Text>
</View>
</View>
);
};
export default React.memo(SlideItem);

View file

@ -0,0 +1,81 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {useIntl} from 'react-intl';
import {StyleSheet} from 'react-native';
import {useTheme} from '@context/theme';
import {OnboardingItem} from '@typings/screens/onboarding';
import CallsSvg from './illustrations/calls';
import ChatSvg from './illustrations/chat';
import IntegrationsSvg from './illustrations/integrations';
import TeamCommunicationSvg from './illustrations/team_communication';
const styles = StyleSheet.create({
image: {
justifyContent: 'center',
height: 200,
},
lastSlideImage: {
height: 250,
left: 8,
},
});
const useSlidesData = () => {
const intl = useIntl();
const theme = useTheme();
const callsSvg = (
<CallsSvg
styles={styles.image}
theme={theme}
/>
);
const chatSvg = (
<ChatSvg
styles={styles.image}
theme={theme}
/>
);
const teamCommunicationSvg = (
<TeamCommunicationSvg
styles={styles.image}
theme={theme}
/>
);
const integrationsSvg = (
<IntegrationsSvg
styles={[styles.image, styles.lastSlideImage]}
theme={theme}
/>
);
const slidesData: OnboardingItem[] = [
{
title: intl.formatMessage({id: 'onboarding.welcome', defaultMessage: 'Welcome'}),
description: intl.formatMessage({id: 'onboaring.welcome_description', defaultMessage: 'Mattermost is an open source platform for developer collaboration. Secure, flexible, and integrated with your tools.'}),
image: chatSvg,
},
{
title: intl.formatMessage({id: 'onboarding.realtime_collaboration', defaultMessage: 'Collaborate in realtime'}),
description: intl.formatMessage({id: 'onboarding.realtime_collaboration_description', defaultMessage: 'Persistent channels, direct messaging, and file sharing works seamlessly so you can stay connected, wherever you are.'}),
image: teamCommunicationSvg,
},
{
title: intl.formatMessage({id: 'onboarding.calls', defaultMessage: 'Start secure audio calls instantly'}),
description: intl.formatMessage({id: 'onboarding.calls_description', defaultMessage: 'When typing isnt fast enough, switch from channel-based chat to secure audio calls with a single tap.'}),
image: callsSvg,
},
{
title: intl.formatMessage({id: 'onboarding.integrations', defaultMessage: 'Integrate with tools you love'}),
description: intl.formatMessage({id: 'onboarding.integrations_description', defaultMessage: 'Go beyond chat with tightly-integrated product solutions matched to common development processes.'}),
image: integrationsSvg,
},
];
return {slidesData};
};
export default useSlidesData;

View file

@ -27,7 +27,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
...typography('Heading', 400, 'SemiBold'),
},
connect: {
width: 270,
width: 320,
letterSpacing: -1,
color: theme.centerChannelColor,
marginVertical: 12,

View file

@ -34,6 +34,7 @@ import ServerHeader from './header';
import type {DeepLinkWithData, LaunchProps} from '@typings/launch';
interface ServerProps extends LaunchProps {
animated?: boolean;
closeButtonId?: string;
componentId: string;
theme: Theme;
@ -46,9 +47,24 @@ const defaultServerUrlMessage = {
defaultMessage: 'Please enter a valid server URL',
};
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
appInfo: {
color: changeOpacity(theme.centerChannelColor, 0.56),
},
flex: {
flex: 1,
},
scrollContainer: {
alignItems: 'center',
height: '100%',
justifyContent: 'center',
},
}));
const AnimatedSafeArea = Animated.createAnimatedComponent(SafeAreaView);
const Server = ({
animated,
closeButtonId,
componentId,
displayName: defaultDisplayName,
@ -61,7 +77,7 @@ const Server = ({
const intl = useIntl();
const managedConfig = useManagedConfig<ManagedConfig>();
const dimensions = useWindowDimensions();
const translateX = useSharedValue(0);
const translateX = useSharedValue(animated ? dimensions.width : 0);
const keyboardAwareRef = useRef<KeyboardAwareScrollView>(null);
const [connecting, setConnecting] = useState(false);
const [displayName, setDisplayName] = useState<string>('');
@ -348,18 +364,4 @@ const Server = ({
);
};
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
appInfo: {
color: changeOpacity(theme.centerChannelColor, 0.56),
},
flex: {
flex: 1,
},
scrollContainer: {
alignItems: 'center',
height: '100%',
justifyContent: 'center',
},
}));
export default Server;

View file

@ -8,6 +8,7 @@ import {Navigation, Options} from 'react-native-navigation';
import {Screens} from '@constants';
export const appearanceControlledScreens = new Set([
Screens.ONBOARDING,
Screens.SERVER,
Screens.LOGIN,
Screens.FORGOT_PASSWORD,

View file

@ -6,7 +6,7 @@ import {StyleSheet, TextStyle} from 'react-native';
// type FontFamilies = 'OpenSans' | 'Metropolis';
type FontTypes = 'Heading' | 'Body';
type FontStyles = 'SemiBold' | 'Regular' | 'Light';
type FontSizes = 25 | 50 | 75 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 1000;
type FontSizes = 25 | 50 | 75 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900 | 1000 | 1200;
const fontFamily = StyleSheet.create({
OpenSans: {
@ -30,6 +30,11 @@ const fontStyle = StyleSheet.create({
});
const fontSize = StyleSheet.create({
1200: {
fontSize: 66,
lineHeight: 48,
letterSpacing: -0.02,
},
1000: {
fontSize: 40,
lineHeight: 48,

View file

@ -36,5 +36,6 @@
"ShowSentryDebugOptions": false,
"CustomRequestHeaders": {},
"ShowReview": false
"ShowReview": false,
"ShowOnboarding": false
}

View file

@ -505,6 +505,9 @@
"mobile.oauth.switch_to_browser.error_title": "Sign in error",
"mobile.oauth.switch_to_browser.title": "Redirecting...",
"mobile.oauth.try_again": "Try again",
"mobile.onboarding.next": "Next",
"mobile.onboarding.sign_in": "Sign in",
"mobile.onboarding.sign_in_to_get_started": "Sign in to get started",
"mobile.open_gm.error": "We couldn't open a group message with those users. Please check your connection and try again.",
"mobile.participants.header": "Thread Participants",
"mobile.permission_denied_dismiss": "Don't Allow",
@ -652,6 +655,14 @@
"notification.message_not_found": "Message not found",
"notification.not_channel_member": "This message belongs to a channel where you are not a member.",
"notification.not_team_member": "This message belongs to a team where you are not a member.",
"onboarding.calls": "Start secure audio calls instantly",
"onboarding.calls_description": "When typing isnt fast enough, switch from channel-based chat to secure audio calls with a single tap.",
"onboarding.integrations": "Integrate with tools you love",
"onboarding.integrations_description": "Go beyond chat with tightly-integrated product solutions matched to common development processes.",
"onboarding.realtime_collaboration": "Collaborate in realtime",
"onboarding.realtime_collaboration_description": "Persistent channels, direct messaging, and file sharing works seamlessly so you can stay connected, wherever you are.",
"onboarding.welcome": "Welcome",
"onboaring.welcome_description": "Mattermost is an open source platform for developer collaboration. Secure, flexible, and integrated with your tools.",
"password_send.description": "To reset your password, enter the email address you used to sign up",
"password_send.error": "Please enter a valid email address.",
"password_send.generic_error": "We were unable to send you a reset password link. Please contact your System Admin for assistance.",

View file

@ -170,6 +170,11 @@ lane :configure do
json['ShowReview'] = true
end
# Configure Show Onboarding
if ENV['SHOW_ONBOARDING'] == 'true'
json['ShowOnboarding'] = true
end
# Save the config.json file
save_json_as_file('../dist/assets/config.json', json)

View file

@ -63,7 +63,7 @@
"*": ["./*", "node_modules/*"],
}
},
"include": ["app/**/*", "share_extensionn/**/*", "test/**/*", "types/**/*"],
"include": ["app/**/*", "share_extension/**/*", "test/**/*", "types/**/*"],
"exclude": [
"node_modules",
"build",

View file

@ -0,0 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
export type OnboardingItem = {
title: string;
description: string;
image: React.ReactElement;
};