[IMPROVEMENT] Add loading message on long running tasks (#1798)

Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
Djorkaeff Alexandre 2020-02-28 17:11:08 -03:00 committed by GitHub
parent ea4f3797ff
commit b67d1dd73d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 65 additions and 29 deletions

View File

@ -1,10 +1,11 @@
import * as types from '../constants/types'; import * as types from '../constants/types';
import { APP } from './actionsTypes'; import { APP } from './actionsTypes';
export function appStart(root) { export function appStart(root, text) {
return { return {
type: APP.START, type: APP.START,
root root,
text
}; };
} }

View File

@ -130,6 +130,7 @@ export default {
Click_to_join: 'Click to Join!', Click_to_join: 'Click to Join!',
Close: 'Close', Close: 'Close',
Close_emoji_selector: 'Close emoji selector', Close_emoji_selector: 'Close emoji selector',
Change_language_loading: 'Changing language.',
Choose: 'Choose', Choose: 'Choose',
Choose_from_library: 'Choose from library', Choose_from_library: 'Choose from library',
Choose_file: 'Choose file', Choose_file: 'Choose file',
@ -150,6 +151,7 @@ export default {
Permalink: 'Permalink', Permalink: 'Permalink',
Certificate_password: 'Certificate Password', Certificate_password: 'Certificate Password',
Clear_cache: 'Clear local server cache', Clear_cache: 'Clear local server cache',
Clear_cache_loading: 'Clearing cache.',
Whats_the_password_for_your_certificate: 'What\'s the password for your certificate?', Whats_the_password_for_your_certificate: 'What\'s the password for your certificate?',
Create_account: 'Create an account', Create_account: 'Create an account',
Create_Channel: 'Create Channel', Create_Channel: 'Create Channel',
@ -235,6 +237,7 @@ export default {
Login: 'Login', Login: 'Login',
Login_error: 'Your credentials were rejected! Please try again.', Login_error: 'Your credentials were rejected! Please try again.',
Login_with: 'Login with', Login_with: 'Login with',
Logging_out: 'Logging out.',
Logout: 'Logout', Logout: 'Logout',
Max_number_of_uses: 'Max number of uses', Max_number_of_uses: 'Max number of uses',
members: 'members', members: 'members',
@ -301,6 +304,7 @@ export default {
pinned: 'pinned', pinned: 'pinned',
Pinned: 'Pinned', Pinned: 'Pinned',
Please_enter_your_password: 'Please enter your password', Please_enter_your_password: 'Please enter your password',
Please_wait: 'Please wait.',
Preferences: 'Preferences', Preferences: 'Preferences',
Preferences_saved: 'Preferences saved!', Preferences_saved: 'Preferences saved!',
Privacy_Policy: ' Privacy Policy', Privacy_Policy: ' Privacy Policy',

View File

@ -128,7 +128,9 @@ export default {
Channel_Name: 'Nome do Canal', Channel_Name: 'Nome do Canal',
Channels: 'Canais', Channels: 'Canais',
Chats: 'Conversas', Chats: 'Conversas',
Change_language_loading: 'Alterando idioma.',
Call_already_ended: 'A chamada já terminou!', Call_already_ended: 'A chamada já terminou!',
Clear_cache_loading: 'Limpando cache.',
Click_to_join: 'Clique para participar!', Click_to_join: 'Clique para participar!',
Close: 'Fechar', Close: 'Fechar',
Close_emoji_selector: 'Fechar seletor de emojis', Close_emoji_selector: 'Fechar seletor de emojis',
@ -222,6 +224,7 @@ export default {
Login_error: 'Suas credenciais foram rejeitadas. Tente novamente por favor!', Login_error: 'Suas credenciais foram rejeitadas. Tente novamente por favor!',
Login_with: 'Login with', Login_with: 'Login with',
Logout: 'Sair', Logout: 'Sair',
Logging_out: 'Saindo.',
Max_number_of_uses: 'Número máximo de usos', Max_number_of_uses: 'Número máximo de usos',
Members: 'Membros', Members: 'Membros',
Mentioned_Messages: 'Mensagens mencionadas', Mentioned_Messages: 'Mensagens mencionadas',
@ -276,6 +279,7 @@ export default {
Pinned_Messages: 'Mensagens Fixadas', Pinned_Messages: 'Mensagens Fixadas',
pinned: 'fixada', pinned: 'fixada',
Pinned: 'Mensagens Fixadas', Pinned: 'Mensagens Fixadas',
Please_wait: 'Por favor, aguarde.',
Please_enter_your_password: 'Por favor, digite sua senha', Please_enter_your_password: 'Por favor, digite sua senha',
Preferences: 'Preferências', Preferences: 'Preferências',
Preferences_saved: 'Preferências salvas!', Preferences_saved: 'Preferências salvas!',

View File

@ -110,7 +110,7 @@ const restore = function* restore() {
} }
}; };
const start = function* start({ root }) { const start = function* start({ root, text }) {
if (root === 'inside') { if (root === 'inside') {
yield Navigation.navigate('InsideStack'); yield Navigation.navigate('InsideStack');
} else if (root === 'setUsername') { } else if (root === 'setUsername') {
@ -118,7 +118,7 @@ const start = function* start({ root }) {
} else if (root === 'outside') { } else if (root === 'outside') {
yield Navigation.navigate('OutsideStack'); yield Navigation.navigate('OutsideStack');
} else if (root === 'loading') { } else if (root === 'loading') {
yield Navigation.navigate('AuthLoading'); yield Navigation.navigate('AuthLoading', { text });
} }
RNBootSplash.hide(); RNBootSplash.hide();
}; };

View File

@ -147,7 +147,7 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) {
}; };
const handleLogout = function* handleLogout({ forcedByServer }) { const handleLogout = function* handleLogout({ forcedByServer }) {
yield put(appStart('loading')); yield put(appStart('loading', I18n.t('Logging_out')));
const server = yield select(getServer); const server = yield select(getServer);
if (server) { if (server) {
try { try {

View File

@ -1,10 +1,40 @@
import React from 'react'; import React from 'react';
import {
View, Text, StyleSheet, ActivityIndicator
} from 'react-native';
import I18n from '../i18n';
import StatusBar from '../containers/StatusBar'; import StatusBar from '../containers/StatusBar';
import { withTheme } from '../theme'; import { withTheme } from '../theme';
import { themes } from '../constants/colors';
export default React.memo(withTheme(({ theme }) => ( import sharedStyles from './Styles';
<>
<StatusBar theme={theme} /> const styles = StyleSheet.create({
</> container: {
))); flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
text: {
fontSize: 16,
paddingTop: 10,
...sharedStyles.textRegular,
...sharedStyles.textAlignCenter
}
});
export default React.memo(withTheme(({ theme, navigation }) => {
const text = navigation.getParam('text');
return (
<View style={[styles.container, { backgroundColor: themes[theme].backgroundColor }]}>
<StatusBar theme={theme} />
{text && (
<>
<ActivityIndicator color={themes[theme].auxiliaryText} size='large' />
<Text style={[styles.text, { color: themes[theme].bodyText }]}>{`${ text }.\n${ I18n.t('Please_wait') }`}</Text>
</>
)}
</View>
);
}));

View File

@ -6,7 +6,6 @@ import { SafeAreaView } from 'react-navigation';
import RocketChat from '../../lib/rocketchat'; import RocketChat from '../../lib/rocketchat';
import I18n from '../../i18n'; import I18n from '../../i18n';
import Loading from '../../containers/Loading';
import { showErrorAlert } from '../../utils/info'; import { showErrorAlert } from '../../utils/info';
import log from '../../utils/log'; import log from '../../utils/log';
import { setUser as setUserAction } from '../../actions/login'; import { setUser as setUserAction } from '../../actions/login';
@ -75,13 +74,12 @@ class LanguageView extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
language: props.user ? props.user.language : 'en', language: props.user ? props.user.language : 'en'
saving: false
}; };
} }
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
const { language, saving } = this.state; const { language } = this.state;
const { user, theme } = this.props; const { user, theme } = this.props;
if (nextProps.theme !== theme) { if (nextProps.theme !== theme) {
return true; return true;
@ -89,9 +87,6 @@ class LanguageView extends React.Component {
if (nextState.language !== language) { if (nextState.language !== language) {
return true; return true;
} }
if (nextState.saving !== saving) {
return true;
}
if (nextProps.user.language !== user.language) { if (nextProps.user.language !== user.language) {
return true; return true;
} }
@ -108,9 +103,18 @@ class LanguageView extends React.Component {
return; return;
} }
this.setState({ saving: true }); const { appStart } = this.props;
const { user, setUser, appStart } = this.props; await appStart('loading', I18n.t('Change_language_loading'));
// shows loading for at least 300ms
await Promise.all([this.changeLanguage(language), new Promise(resolve => setTimeout(resolve, 300))]);
await appStart('inside');
}
changeLanguage = async(language) => {
const { user, setUser } = this.props;
const params = {}; const params = {};
@ -135,15 +139,10 @@ class LanguageView extends React.Component {
// do nothing // do nothing
} }
}); });
await appStart('loading');
await appStart('inside');
} catch (e) { } catch (e) {
showErrorAlert(I18n.t('There_was_an_error_while_action', { action: I18n.t('saving_preferences') })); showErrorAlert(I18n.t('There_was_an_error_while_action', { action: I18n.t('saving_preferences') }));
log(e); log(e);
} }
this.setState({ saving: false });
} }
renderSeparator = () => { renderSeparator = () => {
@ -174,7 +173,6 @@ class LanguageView extends React.Component {
} }
render() { render() {
const { saving } = this.state;
const { theme } = this.props; const { theme } = this.props;
return ( return (
<SafeAreaView <SafeAreaView
@ -196,7 +194,6 @@ class LanguageView extends React.Component {
renderItem={this.renderItem} renderItem={this.renderItem}
ItemSeparatorComponent={this.renderSeparator} ItemSeparatorComponent={this.renderSeparator}
/> />
<Loading visible={saving} />
</SafeAreaView> </SafeAreaView>
); );
} }
@ -208,7 +205,7 @@ const mapStateToProps = state => ({
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({
setUser: params => dispatch(setUserAction(params)), setUser: params => dispatch(setUserAction(params)),
appStart: params => dispatch(appStartAction(params)) appStart: (...params) => dispatch(appStartAction(...params))
}); });
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(LanguageView)); export default connect(mapStateToProps, mapDispatchToProps)(withTheme(LanguageView));

View File

@ -108,7 +108,7 @@ class SettingsView extends React.Component {
const { const {
server: { server }, loginRequest, token, appStart server: { server }, loginRequest, token, appStart
} = this.props; } = this.props;
await appStart('loading'); await appStart('loading', I18n.t('Clear_cache_loading'));
await RocketChat.clearCache({ server }); await RocketChat.clearCache({ server });
await loginRequest({ resume: token }, true); await loginRequest({ resume: token }, true);
} }
@ -350,7 +350,7 @@ const mapDispatchToProps = dispatch => ({
logout: () => dispatch(logoutAction()), logout: () => dispatch(logoutAction()),
loginRequest: (...params) => dispatch(loginRequestAction(...params)), loginRequest: (...params) => dispatch(loginRequestAction(...params)),
toggleCrashReport: params => dispatch(toggleCrashReportAction(params)), toggleCrashReport: params => dispatch(toggleCrashReportAction(params)),
appStart: params => dispatch(appStartAction(params)) appStart: (...params) => dispatch(appStartAction(...params))
}); });
export default connect(mapStateToProps, mapDispatchToProps)(withTheme(withSplit(SettingsView))); export default connect(mapStateToProps, mapDispatchToProps)(withTheme(withSplit(SettingsView)));