diff --git a/app/Icons.js b/app/Icons.js deleted file mode 100644 index 29fdb18a..00000000 --- a/app/Icons.js +++ /dev/null @@ -1,25 +0,0 @@ -import Ionicons from 'react-native-vector-icons/Ionicons'; -import { isIOS } from './utils/deviceInfo'; - -const prefix = isIOS ? 'ios' : 'md'; - -// icon name from provider: [ size of the uri, icon provider, name to be used later ] -const icons = { - [`${ prefix }-star`]: [25, Ionicons, 'star'], - [`${ prefix }-star-outline`]: [25, Ionicons, 'starOutline'], - [`${ prefix }-more`]: [25, Ionicons, 'more'], - [isIOS ? 'ios-create' : 'md-create']: [25, Ionicons, 'create'], - [`${ prefix }-close`]: [25, Ionicons, 'close'] -}; - -const iconsMap = {}; -const iconsLoaded = async() => { - const promises = Object.keys(icons).map((icon) => { - const Provider = icons[icon][1]; - return Provider.getImageSource(icon, icons[icon][0], '#FFF'); - }); - const sources = await Promise.all(promises); - Object.keys(icons).forEach((icon, i) => (iconsMap[icons[icon][2]] = sources[i])); -}; - -export { iconsLoaded, iconsMap }; diff --git a/app/index.js b/app/index.js index 324288ba..289e8fbd 100644 --- a/app/index.js +++ b/app/index.js @@ -1,11 +1,11 @@ import { Component } from 'react'; import { Linking } from 'react-native'; -import store from './lib/createStore'; import { appInit } from './actions'; -import { iconsLoaded } from './Icons'; -import Navigation from './lib/Navigation'; import { deepLinkingOpen } from './actions/deepLinking'; +import store from './lib/createStore'; +import Icons from './lib/Icons'; +import Navigation from './lib/Navigation'; import parseQuery from './lib/methods/helpers/parseQuery'; import { initializePushNotifications } from './push'; import { DEFAULT_HEADER } from './constants/headerOptions'; @@ -95,7 +95,7 @@ const handleOpenURL = ({ url }) => { } }; -iconsLoaded(); +Icons.configure(); export default class App extends Component { constructor(props) { diff --git a/app/lib/Icons.js b/app/lib/Icons.js new file mode 100644 index 00000000..874a7852 --- /dev/null +++ b/app/lib/Icons.js @@ -0,0 +1,50 @@ +import { Dimensions } from 'react-native'; +import Ionicons from 'react-native-vector-icons/Ionicons'; +import { isIOS, isAndroid } from '../utils/deviceInfo'; + +const prefix = isIOS ? 'ios' : 'md'; + +// icon name from provider: [ size of the uri, icon provider, name to be used later ] +const icons = { + [`${ prefix }-star`]: [25, Ionicons, 'star'], + [`${ prefix }-star-outline`]: [25, Ionicons, 'starOutline'], + [`${ prefix }-more`]: [25, Ionicons, 'more'], + [`${ prefix }-create`]: [25, Ionicons, 'create'], + [`${ prefix }-close`]: [25, Ionicons, 'close'] +}; + +if (__DEV__) { + icons[`${ prefix }-settings`] = [25, Ionicons, 'settings']; + icons[`${ prefix }-add`] = [25, Ionicons, 'new_channel']; + icons[`${ prefix }-more`] = [25, Ionicons, 'more']; + if (isAndroid) { + icons[`${ prefix }-search`] = [25, Ionicons, 'search']; + icons[`${ prefix }-arrow-back`] = [25, Ionicons, 'back']; + } +} + +class Icons { + constructor() { + this.icons = {}; + } + + async configure() { + const promises = Object.keys(icons).map((icon) => { + const Provider = icons[icon][1]; + return Provider.getImageSource(icon, icons[icon][0], '#FFF'); + }); + const sources = await Promise.all(promises); + Object.keys(icons).forEach((icon, i) => (this.icons[icons[icon][2]] = sources[i])); + } + + isAndroidDev = () => __DEV__ && isAndroid + + getSource(icon, native = true) { + if (this.isAndroidDev() || !native) { + return this.icons[icon]; + } + return { uri: icon, scale: Dimensions.get('window').scale }; + } +} + +export default new Icons(); diff --git a/app/views/LegalView.js b/app/views/LegalView.js index 3e7374c7..02122b60 100644 --- a/app/views/LegalView.js +++ b/app/views/LegalView.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { - Text, ScrollView, View, StyleSheet, Image, Dimensions + Text, ScrollView, View, StyleSheet, Image } from 'react-native'; import SafeAreaView from 'react-native-safe-area-view'; import { RectButton } from 'react-native-gesture-handler'; @@ -13,6 +13,7 @@ import { isIOS, isAndroid } from '../utils/deviceInfo'; import LoggedView from './View'; import I18n from '../i18n'; import { DARK_HEADER } from '../constants/headerOptions'; +import Icons from '../lib/Icons'; const styles = StyleSheet.create({ container: { @@ -68,7 +69,7 @@ export default class LegalView extends LoggedView { }, leftButtons: [{ id: 'close', - icon: isAndroid ? { uri: 'back', scale: Dimensions.get('window').scale } : undefined, + icon: isAndroid ? Icons.getSource('back') : undefined, text: isIOS ? I18n.t('Close') : undefined, testID: 'legal-view-close' }] diff --git a/app/views/LoginSignupView.js b/app/views/LoginSignupView.js index 8e0da021..61277879 100644 --- a/app/views/LoginSignupView.js +++ b/app/views/LoginSignupView.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { - Text, View, ScrollView, Image, StyleSheet, Dimensions, Animated, Easing + Text, View, ScrollView, Image, StyleSheet, Animated, Easing } from 'react-native'; import { connect } from 'react-redux'; import { Base64 } from 'js-base64'; @@ -17,6 +17,7 @@ import random from '../utils/random'; import Button from '../containers/Button'; import I18n from '../i18n'; import { DARK_HEADER } from '../constants/headerOptions'; +import Icons from '../lib/Icons'; const styles = StyleSheet.create({ container: { @@ -102,7 +103,7 @@ export default class LoginSignupView extends LoggedView { ...DARK_HEADER.topBar, rightButtons: [{ id: 'more', - icon: { uri: 'more', scale: Dimensions.get('window').scale }, + icon: Icons.getSource('more'), testID: 'welcome-view-more' }] } diff --git a/app/views/LoginView.js b/app/views/LoginView.js index 844fdf6b..f54c9632 100644 --- a/app/views/LoginView.js +++ b/app/views/LoginView.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { - Keyboard, Text, ScrollView, View, StyleSheet, Alert, LayoutAnimation, Dimensions + Keyboard, Text, ScrollView, View, StyleSheet, Alert, LayoutAnimation } from 'react-native'; import { connect } from 'react-redux'; import { Answers } from 'react-native-fabric'; @@ -18,6 +18,7 @@ import LoggedView from './View'; import I18n from '../i18n'; import { DARK_HEADER } from '../constants/headerOptions'; import { loginRequest as loginRequestAction } from '../actions/login'; +import Icons from '../lib/Icons'; const styles = StyleSheet.create({ buttonsContainer: { @@ -64,7 +65,7 @@ export default class LoginView extends LoggedView { ...DARK_HEADER.topBar, rightButtons: [{ id: 'more', - icon: { uri: 'more', scale: Dimensions.get('window').scale }, + icon: Icons.getSource('more'), testID: 'login-view-more' }] } diff --git a/app/views/NewMessageView.js b/app/views/NewMessageView.js index 91d28ab6..c52438d2 100644 --- a/app/views/NewMessageView.js +++ b/app/views/NewMessageView.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { - View, StyleSheet, FlatList, Text, Image, Dimensions + View, StyleSheet, FlatList, Text, Image } from 'react-native'; import { connect } from 'react-redux'; import SafeAreaView from 'react-native-safe-area-view'; @@ -18,6 +18,7 @@ import I18n from '../i18n'; import Touch from '../utils/touch'; import { isIOS, isAndroid } from '../utils/deviceInfo'; import SearchBox from '../containers/SearchBox'; +import Icons from '../lib/Icons'; const styles = StyleSheet.create({ safeAreaView: { @@ -57,7 +58,7 @@ export default class NewMessageView extends LoggedView { topBar: { leftButtons: [{ id: 'cancel', - icon: isAndroid ? { uri: 'back', scale: Dimensions.get('window').scale } : undefined, + icon: isAndroid ? Icons.getSource('back') : undefined, text: isIOS ? I18n.t('Cancel') : undefined }] } diff --git a/app/views/OAuthView.js b/app/views/OAuthView.js index dce2a61e..0ab7b21b 100644 --- a/app/views/OAuthView.js +++ b/app/views/OAuthView.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { WebView, Dimensions } from 'react-native'; +import { WebView } from 'react-native'; import { connect } from 'react-redux'; import Navigation from '../lib/Navigation'; @@ -8,6 +8,7 @@ import RocketChat from '../lib/rocketchat'; import I18n from '../i18n'; import { DARK_HEADER } from '../constants/headerOptions'; import { isIOS, isAndroid } from '../utils/deviceInfo'; +import Icons from '../lib/Icons'; const userAgentAndroid = 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1'; const userAgent = isIOS ? 'UserAgent' : userAgentAndroid; @@ -23,7 +24,7 @@ export default class OAuthView extends React.PureComponent { ...DARK_HEADER.topBar, leftButtons: [{ id: 'cancel', - icon: isAndroid ? { uri: 'back', scale: Dimensions.get('window').scale } : undefined, + icon: isAndroid ? Icons.getSource('back') : undefined, text: isIOS ? I18n.t('Cancel') : undefined }] } diff --git a/app/views/ProfileView/index.js b/app/views/ProfileView/index.js index 1f1ae1b0..31cb9122 100644 --- a/app/views/ProfileView/index.js +++ b/app/views/ProfileView/index.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { - View, ScrollView, Keyboard, Dimensions, BackHandler + View, ScrollView, Keyboard, BackHandler } from 'react-native'; import { connect } from 'react-redux'; import Dialog from 'react-native-dialog'; @@ -28,6 +28,7 @@ import Avatar from '../../containers/Avatar'; import Touch from '../../utils/touch'; import { appStart as appStartAction } from '../../actions'; import { setUser as setUserAction } from '../../actions/login'; +import Icons from '../../lib/Icons'; @connect(state => ({ user: { @@ -50,7 +51,7 @@ export default class ProfileView extends LoggedView { topBar: { leftButtons: [{ id: 'settings', - icon: { uri: 'settings', scale: Dimensions.get('window').scale }, + icon: Icons.getSource('settings'), testID: 'rooms-list-view-sidebar' }], title: { diff --git a/app/views/RegisterView.js b/app/views/RegisterView.js index 2e37a868..08d5588b 100644 --- a/app/views/RegisterView.js +++ b/app/views/RegisterView.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { - Keyboard, Text, ScrollView, Dimensions, Alert + Keyboard, Text, ScrollView, Alert } from 'react-native'; import { connect } from 'react-redux'; import SafeAreaView from 'react-native-safe-area-view'; @@ -18,6 +18,7 @@ import { DARK_HEADER } from '../constants/headerOptions'; import RocketChat from '../lib/rocketchat'; import { loginRequest as loginRequestAction } from '../actions/login'; import isValidEmail from '../utils/isValidEmail'; +import Icons from '../lib/Icons'; const shouldUpdateState = ['name', 'email', 'password', 'username', 'saving']; @@ -33,7 +34,7 @@ export default class RegisterView extends LoggedView { ...DARK_HEADER.topBar, rightButtons: [{ id: 'more', - icon: { uri: 'more', scale: Dimensions.get('window').scale }, + icon: Icons.getSource('more'), testID: 'register-view-more' }] } diff --git a/app/views/RoomInfoView/index.js b/app/views/RoomInfoView/index.js index 0de7f13d..3ce9aabe 100644 --- a/app/views/RoomInfoView/index.js +++ b/app/views/RoomInfoView/index.js @@ -17,7 +17,7 @@ import RocketChat from '../../lib/rocketchat'; import log from '../../utils/log'; import RoomTypeIcon from '../../containers/RoomTypeIcon'; import I18n from '../../i18n'; -import { iconsMap } from '../../Icons'; +import Icons from '../../lib/Icons'; const PERMISSION_EDIT_ROOM = 'edit-room'; @@ -94,7 +94,7 @@ export default class RoomInfoView extends LoggedView { topBar: { rightButtons: [{ id: 'edit', - icon: iconsMap.create, + icon: Icons.getSource('create', false), testID: 'room-info-view-edit-button' }] } diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js index 02f40918..45ab88ca 100644 --- a/app/views/RoomView/index.js +++ b/app/views/RoomView/index.js @@ -25,7 +25,7 @@ import styles from './styles'; import log from '../../utils/log'; import { isIOS } from '../../utils/deviceInfo'; import I18n from '../../i18n'; -import { iconsMap } from '../../Icons'; +import Icons from '../../lib/Icons'; import ConnectionBadge from '../../containers/ConnectionBadge'; @connect(state => ({ @@ -59,11 +59,11 @@ export default class RoomView extends LoggedView { rightButtons: [{ id: 'more', testID: 'room-view-header-actions', - icon: iconsMap.more + icon: Icons.getSource('more', false) }, { id: 'star', testID: 'room-view-header-star', - icon: iconsMap.starOutline + icon: Icons.getSource('starOutline', false) }] }, blurOnUnmount: true @@ -156,13 +156,13 @@ export default class RoomView extends LoggedView { const rightButtons = [{ id: 'star', testID: 'room-view-header-star', - icon: room.f ? iconsMap.star : iconsMap.starOutline + icon: room.f ? Icons.getSource('star', false) : Icons.getSource('starOutline', false) }]; if (room.t !== 'l') { rightButtons.unshift({ id: 'more', testID: 'room-view-header-actions', - icon: iconsMap.more + icon: Icons.getSource('more', false) }); } Navigation.mergeOptions(componentId, { diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js index c4805cbb..143a24d4 100644 --- a/app/views/RoomsListView/index.js +++ b/app/views/RoomsListView/index.js @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { - View, FlatList, BackHandler, ActivityIndicator, Text, Image, Dimensions, ScrollView, Keyboard, LayoutAnimation + View, FlatList, BackHandler, ActivityIndicator, Text, Image, ScrollView, Keyboard, LayoutAnimation } from 'react-native'; import { connect } from 'react-redux'; import { isEqual } from 'lodash'; @@ -24,6 +24,7 @@ import { toggleSortDropdown as toggleSortDropdownAction, openSearchHeader as ope import { appStart as appStartAction } from '../../actions'; import debounce from '../../utils/debounce'; import { isIOS, isAndroid } from '../../utils/deviceInfo'; +import Icons from '../../lib/Icons'; const ROW_HEIGHT = 70; const SCROLL_OFFSET = 56; @@ -34,19 +35,19 @@ const keyExtractor = item => item.rid; const leftButtons = [{ id: 'settings', - icon: { uri: 'settings', scale: Dimensions.get('window').scale }, + icon: Icons.getSource('settings'), testID: 'rooms-list-view-sidebar' }]; const rightButtons = [{ id: 'newMessage', - icon: { uri: 'new_channel', scale: Dimensions.get('window').scale }, + icon: Icons.getSource('new_channel'), testID: 'rooms-list-view-create-channel' }]; if (isAndroid) { rightButtons.push({ id: 'search', - icon: { uri: 'search', scale: Dimensions.get('window').scale } + icon: Icons.getSource('search') }); } @@ -378,7 +379,7 @@ export default class RoomsListView extends LoggedView { topBar: { leftButtons: [{ id: 'back', - icon: { uri: 'back', scale: Dimensions.get('window').scale }, + icon: Icons.getSource('back'), testID: 'rooms-list-view-cancel-search' }], rightButtons: [] diff --git a/app/views/SettingsView/index.js b/app/views/SettingsView/index.js index b5d4e460..ee8e3a18 100644 --- a/app/views/SettingsView/index.js +++ b/app/views/SettingsView/index.js @@ -1,8 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { - View, ScrollView, Dimensions, BackHandler -} from 'react-native'; +import { View, ScrollView, BackHandler } from 'react-native'; import RNPickerSelect from 'react-native-picker-select'; import { connect } from 'react-redux'; import SafeAreaView from 'react-native-safe-area-view'; @@ -21,6 +19,7 @@ import { showErrorAlert, showToast } from '../../utils/info'; import log from '../../utils/log'; import { setUser as setUserAction } from '../../actions/login'; import { appStart as appStartAction } from '../../actions'; +import Icons from '../../lib/Icons'; @connect(state => ({ userLanguage: state.login.user && state.login.user.language @@ -35,7 +34,7 @@ export default class SettingsView extends LoggedView { topBar: { leftButtons: [{ id: 'settings', - icon: { uri: 'settings', scale: Dimensions.get('window').scale }, + icon: Icons.getSource('settings'), testID: 'rooms-list-view-sidebar' }], title: {