PLT-3640 Add mobile landing pages (#3674)
* PLT-3640 Moved all clientside user agent snooping into a single file * PLT-3640 Added mobile landing pages on login to iOS and Android web apps * PLT-3640 Moved landing page to appear before first login * PLT-3640 Fixed detection of Chrome on Android * PLT-3640 Disabled mobile landing pages when their respective URLs are set to blank
Этот коммит содержится в:
коммит произвёл
Corey Hulen
родитель
790dd91e7d
Коммит
1de3bd3b43
@@ -8,6 +8,7 @@ import Client from 'client/web_client.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
import ChannelStore from 'stores/channel_store.jsx';
|
||||
import DelayedAction from 'utils/delayed_action.jsx';
|
||||
import * as UserAgent from 'utils/user_agent.jsx';
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
|
||||
import {intlShape, injectIntl, defineMessages} from 'react-intl';
|
||||
@@ -311,13 +312,13 @@ class FileUpload extends React.Component {
|
||||
|
||||
render() {
|
||||
let multiple = true;
|
||||
if (Utils.isMobileApp()) {
|
||||
if (UserAgent.isMobileApp()) {
|
||||
// iOS WebViews don't upload videos properly in multiple mode
|
||||
multiple = false;
|
||||
}
|
||||
|
||||
let accept = '';
|
||||
if (Utils.isIosChrome()) {
|
||||
if (UserAgent.isIosChrome()) {
|
||||
// iOS Chrome can't upload videos at all
|
||||
accept = 'image/*';
|
||||
}
|
||||
|
||||
75
webapp/components/get_android_app/get_android_app.jsx
Обычный файл
75
webapp/components/get_android_app/get_android_app.jsx
Обычный файл
@@ -0,0 +1,75 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {Link} from 'react-router';
|
||||
|
||||
import MattermostIcon from 'images/favicon/android-chrome-192x192.png';
|
||||
import Nexus6Mockup from 'images/nexus-6p-mockup.png';
|
||||
|
||||
export default class GetAndroidApp extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div className='get-app get-android-app'>
|
||||
<h1 className='get-app__header'>
|
||||
<FormattedMessage
|
||||
id='get_app.androidHeader'
|
||||
defaultMessage='Mattermost works best if you switch to our Android app'
|
||||
/>
|
||||
</h1>
|
||||
<hr/>
|
||||
<div>
|
||||
<img
|
||||
className='get-android-app__icon'
|
||||
src={MattermostIcon}
|
||||
/>
|
||||
<div className='get-android-app__app-info'>
|
||||
<span className='get-android-app__app-name'>
|
||||
<FormattedMessage
|
||||
id='get_app.androidAppName'
|
||||
defaultMessage='Mattermost for Android'
|
||||
/>
|
||||
</span>
|
||||
<span className='get-android-app__app-creator'>
|
||||
<FormattedMessage
|
||||
id='get_app.mattermostInc'
|
||||
defaultMessage='Mattermost, Inc'
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
className='btn btn-primary get-android-app__continue'
|
||||
href={global.window.mm_config.AndroidAppDownloadLink}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='get_app.continue'
|
||||
defaultMessage='Continue'
|
||||
/>
|
||||
</a>
|
||||
<img
|
||||
className='get-app__screenshot'
|
||||
src={Nexus6Mockup}
|
||||
/>
|
||||
<span className='get-app__continue-with-browser'>
|
||||
<FormattedMessage
|
||||
id='get_app.continueWithBrowser'
|
||||
defaultMessage='Or {link}'
|
||||
values={{
|
||||
link: (
|
||||
<Link to='/switch_team'>
|
||||
<FormattedMessage
|
||||
id='get_app.continueWithBrowserLink'
|
||||
defaultMessage='continue with browser'
|
||||
/>
|
||||
</Link>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
68
webapp/components/get_ios_app/get_ios_app.jsx
Обычный файл
68
webapp/components/get_ios_app/get_ios_app.jsx
Обычный файл
@@ -0,0 +1,68 @@
|
||||
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {Link} from 'react-router';
|
||||
|
||||
import AppStoreButton from 'images/app-store-button.png';
|
||||
import IPhone6Mockup from 'images/iphone-6-mockup.png';
|
||||
|
||||
export default class GetIosApp extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div className='get-app get-ios-app'>
|
||||
<h1 className='get-app__header'>
|
||||
<FormattedMessage
|
||||
id='get_app.iosHeader'
|
||||
defaultMessage='Mattermost works best if you switch to our iPhone app'
|
||||
/>
|
||||
</h1>
|
||||
<hr/>
|
||||
<a
|
||||
className='get-ios-app__app-store-link'
|
||||
href={global.window.mm_config.IosAppDownloadLink}
|
||||
rel='noopener noreferrer'
|
||||
>
|
||||
<img src={AppStoreButton}/>
|
||||
</a>
|
||||
<img
|
||||
className='get-app__screenshot'
|
||||
src={IPhone6Mockup}
|
||||
/>
|
||||
<h2 className='get-ios-app__already-have-it'>
|
||||
<FormattedMessage
|
||||
id='get_app.alreadyHaveIt'
|
||||
defaultMessage='Already have it?'
|
||||
/>
|
||||
</h2>
|
||||
<a
|
||||
className='btn btn-primary get-ios-app__open-mattermost'
|
||||
href='mattermost://'
|
||||
>
|
||||
<FormattedMessage
|
||||
id='get_app.openMattermost'
|
||||
defaultMessage='Open Mattermost'
|
||||
/>
|
||||
</a>
|
||||
<span className='get-app__continue-with-browser'>
|
||||
<FormattedMessage
|
||||
id='get_app.continueWithBrowser'
|
||||
defaultMessage='Or {link}'
|
||||
values={{
|
||||
link: (
|
||||
<Link to='/switch_team'>
|
||||
<FormattedMessage
|
||||
id='get_app.continueWithBrowserLink'
|
||||
defaultMessage='continue with browser'
|
||||
/>
|
||||
</Link>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
import $ from 'jquery';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import * as UserAgent from 'utils/user_agent.jsx';
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
|
||||
@@ -53,9 +54,11 @@ class NewChannelModal extends React.Component {
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (Utils.isBrowserIE()) {
|
||||
// ???
|
||||
if (UserAgent.isInternetExplorer()) {
|
||||
$('body').addClass('browser--ie');
|
||||
}
|
||||
|
||||
PreferenceStore.addChangeListener(this.onPreferenceChange);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import * as GlobalActions from 'actions/global_actions.jsx';
|
||||
|
||||
import {createChannelIntroMessage} from 'utils/channel_intro_messages.jsx';
|
||||
|
||||
import * as UserAgent from 'utils/user_agent.jsx';
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import * as PostUtils from 'utils/post_utils.jsx';
|
||||
import DelayedAction from 'utils/delayed_action.jsx';
|
||||
@@ -336,7 +337,7 @@ export default class PostList extends React.Component {
|
||||
|
||||
// Temporary fix to solve ie11 rendering issue
|
||||
let newSeparatorId = '';
|
||||
if (!Utils.isBrowserIE()) {
|
||||
if (!UserAgent.isInternetExplorer()) {
|
||||
newSeparatorId = 'new_message_' + post.id;
|
||||
}
|
||||
postCtls.push(
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
import TeamStore from 'stores/team_store.jsx';
|
||||
import * as UserAgent from 'utils/user_agent.jsx';
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import ErrorBar from 'components/error_bar.jsx';
|
||||
import LoadingScreen from 'components/loading_screen.jsx';
|
||||
@@ -176,7 +177,7 @@ export default class SelectTeam extends React.Component {
|
||||
}
|
||||
|
||||
let teamSignUp;
|
||||
if (isSystemAdmin || (global.window.mm_config.EnableTeamCreation === 'true' && !Utils.isMobileApp())) {
|
||||
if (isSystemAdmin || (global.window.mm_config.EnableTeamCreation === 'true' && !UserAgent.isMobileApp())) {
|
||||
teamSignUp = (
|
||||
<div className='margin--extra'>
|
||||
<Link
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import $ from 'jquery';
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import * as UserAgent from 'utils/user_agent.jsx';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
@@ -18,7 +18,7 @@ export default class SettingsSidebar extends React.Component {
|
||||
$(e.target).closest('.settings-modal').addClass('display--content');
|
||||
}
|
||||
componentDidMount() {
|
||||
if (Utils.isBrowserFirefox()) {
|
||||
if (UserAgent.isFirefox()) {
|
||||
$('.settings-modal .settings-table .nav').addClass('position--top');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import TeamStore from 'stores/team_store.jsx';
|
||||
import PreferenceStore from 'stores/preference_store.jsx';
|
||||
|
||||
import * as GlobalActions from 'actions/global_actions.jsx';
|
||||
import * as UserAgent from 'utils/user_agent.jsx';
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
|
||||
@@ -296,7 +297,7 @@ export default class SidebarRightMenu extends React.Component {
|
||||
}
|
||||
|
||||
let nativeAppLink = null;
|
||||
if (global.window.mm_config.AppDownloadLink && !Utils.isMobileApp()) {
|
||||
if (global.window.mm_config.AppDownloadLink && !UserAgent.isMobileApp()) {
|
||||
nativeAppLink = (
|
||||
<li>
|
||||
<Link
|
||||
|
||||
@@ -9,13 +9,14 @@ import UserStore from 'stores/user_store.jsx';
|
||||
|
||||
import Client from 'client/web_client.jsx';
|
||||
import * as AsyncClient from 'utils/async_client.jsx';
|
||||
import * as UserAgent from 'utils/user_agent.jsx';
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage} from 'react-intl';
|
||||
|
||||
function getNotificationsStateFromStores() {
|
||||
var user = UserStore.getCurrentUser();
|
||||
var soundNeeded = !Utils.isBrowserFirefox();
|
||||
var soundNeeded = !UserAgent.isFirefox();
|
||||
|
||||
var sound = 'true';
|
||||
if (user.notify_props && user.notify_props.desktop_sound) {
|
||||
|
||||
Ссылка в новой задаче
Block a user