diff --git a/.gitignore b/.gitignore index 5b8a7f05..3762b246 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,5 @@ fastlane/Preview.html fastlane/screenshots coverage + +.vscode/ diff --git a/__tests__/RoomItem.js b/__tests__/RoomItem.js index 1244a443..fbc92f2d 100644 --- a/__tests__/RoomItem.js +++ b/__tests__/RoomItem.js @@ -1,6 +1,6 @@ import 'react-native'; import React from 'react'; -import RoomItem from '../app/components/RoomItem'; +import RoomItem from '../app/presentation/RoomItem'; // Note: test renderer must be required after react-native. import renderer from 'react-test-renderer'; diff --git a/app/components/avatar.js b/app/containers/Avatar.js similarity index 54% rename from app/components/avatar.js rename to app/containers/Avatar.js index 8cc05a7f..fb7c19f5 100644 --- a/app/components/avatar.js +++ b/app/containers/Avatar.js @@ -15,27 +15,42 @@ const styles = StyleSheet.create({ }, avatarInitials: { color: '#ffffff' - } }); + } +}); class Avatar extends React.PureComponent { render() { - const { text = '', size = 25, baseUrl = this.props.baseUrl, - borderRadius = 5, style, avatar } = this.props; + const { text = '', size = 25, baseUrl, borderRadius = 5, style, avatar } = this.props; const { initials, color } = avatarInitialsAndColor(`${ text }`); + + const iconContainerStyle = { + backgroundColor: color, + width: size, + height: size, + borderRadius + }; + + const avatarInitialsStyle = { + fontSize: size / 2 + }; + + const avatarStyle = { + width: size, + height: size + }; + + const uri = avatar || `${ baseUrl }/avatar/${ text }`; + const image = (avatar || baseUrl) && ( + + ); + return ( - - {initials} - { (avatar || baseUrl) && } + + {initials} + {image} ); } } diff --git a/app/components/banner.js b/app/containers/Banner.js similarity index 100% rename from app/components/banner.js rename to app/containers/Banner.js diff --git a/app/components/Message.js b/app/containers/Message.js similarity index 54% rename from app/components/Message.js rename to app/containers/Message.js index b1dee59e..2158244c 100644 --- a/app/components/Message.js +++ b/app/containers/Message.js @@ -1,11 +1,12 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { View, Text, StyleSheet } from 'react-native'; +import { View, StyleSheet } from 'react-native'; import { emojify } from 'react-emojione'; import Markdown from 'react-native-easy-markdown'; -import moment from 'moment'; -import Avatar from './avatar'; -import Card from './message/card'; + +import Card from './message/Card'; +import Avatar from './Avatar'; +import User from './message/User'; const styles = StyleSheet.create({ content: { @@ -17,30 +18,6 @@ const styles = StyleSheet.create({ paddingBottom: 6, flexDirection: 'row', transform: [{ scaleY: -1 }] - }, - texts: { - flex: 1 - }, - msg: { - flex: 1 - }, - username: { - fontWeight: 'bold' - }, - usernameView: { - flexDirection: 'row', - alignItems: 'center', - marginBottom: 2 - }, - alias: { - fontSize: 10, - color: '#888', - paddingLeft: 5 - }, - time: { - fontSize: 10, - color: '#888', - paddingLeft: 5 } }); @@ -50,9 +27,11 @@ export default class Message extends React.PureComponent { baseUrl: PropTypes.string.isRequired, Message_TimeFormat: PropTypes.string.isRequired } + attachments() { return this.props.item.attachments.length ? : null; } + render() { const { item } = this.props; @@ -62,21 +41,23 @@ export default class Message extends React.PureComponent { } const msg = emojify(item.msg, { output: 'unicode' }); - const username = item.alias || item.u.username; - const time = moment(item.ts).format(this.props.Message_TimeFormat); - return ( - + - - - {username} - - {item.alias && @{item.u.username}}{time} - + {this.attachments()} {msg} diff --git a/app/components/MessageBox.js b/app/containers/MessageBox.js similarity index 100% rename from app/components/MessageBox.js rename to app/containers/MessageBox.js diff --git a/app/components/message/card.js b/app/containers/message/Card.js similarity index 93% rename from app/components/message/card.js rename to app/containers/message/Card.js index c039c26d..0d71026f 100644 --- a/app/components/message/card.js +++ b/app/containers/message/Card.js @@ -40,6 +40,7 @@ export default class Cards extends React.PureComponent { data: PropTypes.object.isRequired, base: PropTypes.string } + constructor() { super(); const user = Meteor.user(); @@ -48,6 +49,32 @@ export default class Cards extends React.PureComponent { this.setState({ img: `${ this.props.base }${ this.props.data.image_url }?rc_uid=${ user._id }&rc_token=${ token }` }); }); } + + getImage() { + return ( + this._onPressButton()}> + + + + + + {this.props.data.title} + {this.props.data.description} + + + + ); + } + + getOther() { + return ( + {this.props.data.title} + ); + } + _onPressButton() { Navigation.showModal({ screen: 'Photo', @@ -66,23 +93,8 @@ export default class Cards extends React.PureComponent { animationType: 'slide-up' // 'none' / 'slide-up' , appear animation for the modal (optional, default 'slide-up') }); } + render() { - return this.state.img ? ( - this._onPressButton()}> - - - - - - {this.props.data.title} - {this.props.data.description} - - - - ) : - {this.props.data.title}; + return this.state.img ? this.getImage() : this.getOther(); } } diff --git a/app/containers/message/User.js b/app/containers/message/User.js new file mode 100644 index 00000000..c75d88a3 --- /dev/null +++ b/app/containers/message/User.js @@ -0,0 +1,55 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { View, Text, StyleSheet } from 'react-native'; +import moment from 'moment'; + +const styles = StyleSheet.create({ + username: { + fontWeight: 'bold' + }, + usernameView: { + flexDirection: 'row', + alignItems: 'center', + marginBottom: 2 + }, + alias: { + fontSize: 10, + color: '#888', + paddingLeft: 5 + }, + time: { + fontSize: 10, + color: '#888', + paddingLeft: 5 + } +}); + +export default class Message extends React.PureComponent { + static propTypes = { + item: PropTypes.object.isRequired, + Message_TimeFormat: PropTypes.string.isRequired, + onPress: PropTypes.func + } + + render() { + const { item } = this.props; + + const extraStyle = {}; + if (item.temp) { + extraStyle.opacity = 0.3; + } + + const username = item.alias || item.u.username; + const aliasUsername = item.alias ? (@{item.u.username}) : null; + const time = moment(item.ts).format(this.props.Message_TimeFormat); + + return ( + + + {username} + + {aliasUsername}{time} + + ); + } +} diff --git a/app/components/KeyboardView.js b/app/presentation/KeyboardView.js similarity index 100% rename from app/components/KeyboardView.js rename to app/presentation/KeyboardView.js diff --git a/app/components/RoomItem.js b/app/presentation/RoomItem.js similarity index 98% rename from app/components/RoomItem.js rename to app/presentation/RoomItem.js index b1957787..de65d424 100644 --- a/app/components/RoomItem.js +++ b/app/presentation/RoomItem.js @@ -2,7 +2,7 @@ import React from 'react'; import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; import PropTypes from 'prop-types'; import { View, Text, StyleSheet, TouchableOpacity } from 'react-native'; -import Avatar from './avatar'; +import Avatar from '../containers/Avatar'; import avatarInitialsAndColor from '../utils/avatarInitialsAndColor'; const styles = StyleSheet.create({ @@ -79,14 +79,14 @@ export default class RoomItem extends React.PureComponent { return null; } + const { color } = avatarInitialsAndColor(name); + if (type === 'd') { return ( ); } - const { color } = avatarInitialsAndColor(name); - return ( diff --git a/app/views/CreateChannel.js b/app/views/CreateChannel.js index 45424e05..1f83d83e 100644 --- a/app/views/CreateChannel.js +++ b/app/views/CreateChannel.js @@ -5,7 +5,7 @@ import PropTypes from 'prop-types'; import { TextInput, View, Text, Switch, TouchableOpacity, ScrollView } from 'react-native'; import { createChannelRequest } from '../actions/createChannel'; import styles from './Styles'; -import KeyboardView from '../components/KeyboardView'; +import KeyboardView from '../presentation/KeyboardView'; @connect(state => ({ result: state.createChannel diff --git a/app/views/login.js b/app/views/login.js index 8393ebd9..2534a45b 100644 --- a/app/views/login.js +++ b/app/views/login.js @@ -8,7 +8,7 @@ import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; // import * as actions from '../actions'; import * as loginActions from '../actions/login'; -import KeyboardView from '../components/KeyboardView'; +import KeyboardView from '../presentation/KeyboardView'; // import { Keyboard } from 'react-native' import styles from './Styles'; diff --git a/app/views/room.js b/app/views/room.js index 0060f434..832126ca 100644 --- a/app/views/room.js +++ b/app/views/room.js @@ -10,9 +10,9 @@ import { messagesRequest } from '../actions/messages'; import realm from '../lib/realm'; import RocketChat from '../lib/rocketchat'; import debounce from '../utils/throttle'; -import Message from '../components/Message'; -import MessageBox from '../components/MessageBox'; -import KeyboardView from '../components/KeyboardView'; +import Message from '../containers/Message'; +import MessageBox from '../containers/MessageBox'; +import KeyboardView from '../presentation/KeyboardView'; const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 }); const styles = StyleSheet.create({ diff --git a/app/views/roomsList.js b/app/views/roomsList.js index 559fbfff..f4c8c6b8 100644 --- a/app/views/roomsList.js +++ b/app/views/roomsList.js @@ -10,8 +10,8 @@ import * as actions from '../actions'; import * as server from '../actions/connect'; import realm from '../lib/realm'; import RocketChat from '../lib/rocketchat'; -import RoomItem from '../components/RoomItem'; -import Banner from '../components/banner'; +import RoomItem from '../presentation/RoomItem'; +import Banner from '../containers/Banner'; const styles = StyleSheet.create({ container: { diff --git a/app/views/serverList.js b/app/views/serverList.js index a988ea44..1c71bbf0 100644 --- a/app/views/serverList.js +++ b/app/views/serverList.js @@ -9,7 +9,7 @@ import { connect } from 'react-redux'; import { setServer } from '../actions/server'; import realm from '../lib/realm'; import Fade from '../animations/fade'; -import Banner from '../components/banner'; +import Banner from '../containers/Banner'; const styles = StyleSheet.create({ view: { diff --git a/app/views/serverNew.js b/app/views/serverNew.js index dbac69be..2999fc5c 100644 --- a/app/views/serverNew.js +++ b/app/views/serverNew.js @@ -4,7 +4,7 @@ import { Navigation } from 'react-native-navigation'; import { Text, TextInput, View, StyleSheet } from 'react-native'; import { connect } from 'react-redux'; import { serverRequest, addServer } from '../actions/server'; -import KeyboardView from '../components/KeyboardView'; +import KeyboardView from '../presentation/KeyboardView'; const styles = StyleSheet.create({ view: { diff --git a/storybook/stories/Avatar.js b/storybook/stories/Avatar.js index 204a38bd..40850c51 100644 --- a/storybook/stories/Avatar.js +++ b/storybook/stories/Avatar.js @@ -1,7 +1,7 @@ import React from 'react'; import { ScrollView } from 'react-native'; -import Avatar from '../../app/components/avatar'; +import Avatar from '../../app/containers/Avatar'; export default ( diff --git a/storybook/stories/Channels/DirectMessage.js b/storybook/stories/Channels/DirectMessage.js index 3aacd7c1..8ca1c0d0 100644 --- a/storybook/stories/Channels/DirectMessage.js +++ b/storybook/stories/Channels/DirectMessage.js @@ -1,7 +1,7 @@ import React from 'react'; import { ScrollView } from 'react-native'; -import RoomItem from '../../../app/components/RoomItem'; +import RoomItem from '../../../app/presentation/RoomItem'; export default ( diff --git a/yarn.lock b/yarn.lock index bf786132..3ee65ac6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -19,6 +19,15 @@ dependencies: "@storybook/addons" "^3.2.0" +"@storybook/addon-storyshots@^3.2.6": + version "3.2.8" + resolved "https://registry.yarnpkg.com/@storybook/addon-storyshots/-/addon-storyshots-3.2.8.tgz#f6e9aa6c99a9f437042da49123c0dc75fe51b90f" + dependencies: + babel-runtime "^6.23.0" + global "^4.3.2" + prop-types "^15.5.10" + read-pkg-up "^2.0.0" + "@storybook/addons@^3.2.0": version "3.2.0" resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-3.2.0.tgz#e1446cc5613af179701673276267cee71859bf41" @@ -278,6 +287,10 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +argv@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/argv/-/argv-0.0.2.tgz#ecbd16f8949b157183711b1bda334f37840185ab" + aria-query@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-0.7.0.tgz#4af10a1e61573ddea0cf3b99b51c52c05b424d24" @@ -1072,7 +1085,7 @@ babel-plugin-transform-strict-mode@^6.24.1: babel-runtime "^6.22.0" babel-types "^6.24.1" -babel-polyfill@^6.20.0, babel-polyfill@^6.23.0: +babel-polyfill@^6.20.0, babel-polyfill@^6.23.0, babel-polyfill@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" dependencies: @@ -1794,6 +1807,14 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" +codecov@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/codecov/-/codecov-2.3.0.tgz#ad25a2c6e0442d13740d9d4ddbb9a3e2714330f4" + dependencies: + argv "0.0.2" + request "2.81.0" + urlgrey "0.4.4" + color-convert@^1.3.0, color-convert@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" @@ -5635,20 +5656,12 @@ react-native-action-button@^2.7.2: dependencies: prop-types "^15.5.10" -react-native-auto-grow-textinput@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/react-native-auto-grow-textinput/-/react-native-auto-grow-textinput-1.2.0.tgz#575f2e0fc2c49dbd4fa7fd91ba9f82bdf3409b0c" - -react-native-autogrow-input@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/react-native-autogrow-input/-/react-native-autogrow-input-0.2.1.tgz#4b0fb440b570efdedfde32666036db666d3ac4ec" +react-native-animatable@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/react-native-animatable/-/react-native-animatable-1.2.3.tgz#d0f0bd694833b934f3aaa1275739228b786ecb4b" dependencies: prop-types "^15.5.10" -react-native-autogrow-textinput@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/react-native-autogrow-textinput/-/react-native-autogrow-textinput-4.1.0.tgz#a7e5b17eb3c16ab08e31bbfb88d92488ed87f276" - react-native-card-view@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/react-native-card-view/-/react-native-card-view-0.0.3.tgz#8db9ac4a3f01d08f8bd9f79343082d87fdf09907" @@ -5657,10 +5670,6 @@ react-native-compat@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/react-native-compat/-/react-native-compat-0.0.2.tgz#5d7642f3d53ad324a025893be3c66d16a01cda23" -react-native-console-time-polyfill@0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/react-native-console-time-polyfill/-/react-native-console-time-polyfill-0.0.6.tgz#7823d86fe83439c74480d1b124a92b1a78571889" - react-native-dismiss-keyboard@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/react-native-dismiss-keyboard/-/react-native-dismiss-keyboard-1.0.0.tgz#32886242b3f2317e121f3aeb9b0a585e2b879b49" @@ -5690,11 +5699,7 @@ react-native-fetch-blob@^0.10.8: base-64 "0.1.0" glob "7.0.6" -react-native-form-generator@^0.9.9: - version "0.9.9" - resolved "https://registry.yarnpkg.com/react-native-form-generator/-/react-native-form-generator-0.9.9.tgz#68aae26d1e8dc3e30073ccd7bb298fbdfdce1bca" - -react-native-image-picker@^0.26.3: +react-native-image-picker@^0.26.4: version "0.26.4" resolved "https://registry.yarnpkg.com/react-native-image-picker/-/react-native-image-picker-0.26.4.tgz#e53b0564bef44cb3c96ff81594e1e874daa1f0b3" @@ -5704,6 +5709,10 @@ react-native-img-cache@^1.4.0: dependencies: crypto-js "^3.1.9-1" +react-native-loading-spinner-overlay@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/react-native-loading-spinner-overlay/-/react-native-loading-spinner-overlay-0.5.2.tgz#b7bcd277476d596615fd7feee601789f9bdc7acc" + react-native-meteor@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/react-native-meteor/-/react-native-meteor-1.1.0.tgz#55a91efe2d466d3a8cceb5b5419799aeedcd6756" @@ -6064,9 +6073,9 @@ redux-logger@^3.0.6: dependencies: deep-diff "^0.3.5" -redux-thunk@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.2.0.tgz#e615a16e16b47a19a515766133d1e3e99b7852e5" +redux-saga@^0.15.6: + version "0.15.6" + resolved "https://registry.yarnpkg.com/redux-saga/-/redux-saga-0.15.6.tgz#8638dc522de6c6c0a496fe8b2b5466287ac2dc4d" redux@^3.6.0, redux@^3.7.2: version "3.7.2" @@ -6156,7 +6165,7 @@ replace-ext@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" -request@^2.78.0, request@^2.79.0, request@^2.81.0: +request@2.81.0, request@^2.78.0, request@^2.79.0, request@^2.81.0: version "2.81.0" resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" dependencies: @@ -7001,6 +7010,10 @@ url@^0.11.0: punycode "1.3.2" querystring "0.2.0" +urlgrey@0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/urlgrey/-/urlgrey-0.4.4.tgz#892fe95960805e85519f1cd4389f2cb4cbb7652f" + util-deprecate@1.0.2, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -7417,4 +7430,4 @@ yauzl@2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" dependencies: - fd-slicer "~1.0.1" \ No newline at end of file + fd-slicer "~1.0.1"