diff --git a/__tests__/RoomItem.js b/__tests__/RoomItem.js
index cc4d76d2..253b5d45 100644
--- a/__tests__/RoomItem.js
+++ b/__tests__/RoomItem.js
@@ -3,7 +3,7 @@ import { Provider } from 'react-redux';
import { createStore, combineReducers } from 'redux';
-const reducers = combineReducers({settings:() => ({})});
+const reducers = combineReducers({login:() => ({user: {}}), settings:() => ({})});
const store = createStore(reducers);
import React from 'react';
diff --git a/__tests__/__snapshots__/RoomItem.js.snap b/__tests__/__snapshots__/RoomItem.js.snap
index 23643947..4bb3753e 100644
--- a/__tests__/__snapshots__/RoomItem.js.snap
+++ b/__tests__/__snapshots__/RoomItem.js.snap
@@ -34,9 +34,11 @@ exports[`render channel 1`] = `
Array [
Object {
"alignItems": "center",
+ "borderBottomColor": "#ddd",
+ "borderBottomWidth": 0.5,
"flexDirection": "row",
"paddingHorizontal": 16,
- "paddingVertical": 10,
+ "paddingVertical": 12,
},
undefined,
]
@@ -48,13 +50,12 @@ exports[`render channel 1`] = `
Object {
"alignItems": "center",
"justifyContent": "center",
- "overflow": "hidden",
},
Object {
"backgroundColor": "#00BCD4",
"borderRadius": 4,
- "height": 40,
- "width": 40,
+ "height": 46,
+ "width": 46,
},
undefined,
]
@@ -75,7 +76,7 @@ exports[`render channel 1`] = `
"color": "#ffffff",
},
Object {
- "fontSize": 20,
+ "fontSize": 23,
},
],
Object {
@@ -93,44 +94,70 @@ exports[`render channel 1`] = `
style={
Object {
"flex": 1,
+ "height": "100%",
"marginLeft": 16,
"marginRight": 4,
}
}
>
-
- general
-
-
- Nov 10
-
+
+ general
+
+
+ Nov 10
+
+
+
@@ -171,9 +198,11 @@ exports[`render no icon 1`] = `
Array [
Object {
"alignItems": "center",
+ "borderBottomColor": "#ddd",
+ "borderBottomWidth": 0.5,
"flexDirection": "row",
"paddingHorizontal": 16,
- "paddingVertical": 10,
+ "paddingVertical": 12,
},
undefined,
]
@@ -185,13 +214,12 @@ exports[`render no icon 1`] = `
Object {
"alignItems": "center",
"justifyContent": "center",
- "overflow": "hidden",
},
Object {
"backgroundColor": "#3F51B5",
"borderRadius": 4,
- "height": 40,
- "width": 40,
+ "height": 46,
+ "width": 46,
},
undefined,
]
@@ -212,7 +240,7 @@ exports[`render no icon 1`] = `
"color": "#ffffff",
},
Object {
- "fontSize": 20,
+ "fontSize": 23,
},
],
Object {
@@ -230,44 +258,70 @@ exports[`render no icon 1`] = `
style={
Object {
"flex": 1,
+ "height": "100%",
"marginLeft": 16,
"marginRight": 4,
}
}
>
-
- name
-
-
- Nov 10
-
+
+ name
+
+
+ Nov 10
+
+
+
@@ -308,9 +362,11 @@ exports[`render private group 1`] = `
Array [
Object {
"alignItems": "center",
+ "borderBottomColor": "#ddd",
+ "borderBottomWidth": 0.5,
"flexDirection": "row",
"paddingHorizontal": 16,
- "paddingVertical": 10,
+ "paddingVertical": 12,
},
undefined,
]
@@ -322,13 +378,12 @@ exports[`render private group 1`] = `
Object {
"alignItems": "center",
"justifyContent": "center",
- "overflow": "hidden",
},
Object {
"backgroundColor": "#FF9800",
"borderRadius": 4,
- "height": 40,
- "width": 40,
+ "height": 46,
+ "width": 46,
},
undefined,
]
@@ -349,7 +404,7 @@ exports[`render private group 1`] = `
"color": "#ffffff",
},
Object {
- "fontSize": 20,
+ "fontSize": 23,
},
],
Object {
@@ -367,44 +422,70 @@ exports[`render private group 1`] = `
style={
Object {
"flex": 1,
+ "height": "100%",
"marginLeft": 16,
"marginRight": 4,
}
}
>
-
- private-group
-
-
- Nov 10
-
+
+ private-group
+
+
+ Nov 10
+
+
+
@@ -446,9 +527,11 @@ exports[`render unread +999 1`] = `
Array [
Object {
"alignItems": "center",
+ "borderBottomColor": "#ddd",
+ "borderBottomWidth": 0.5,
"flexDirection": "row",
"paddingHorizontal": 16,
- "paddingVertical": 10,
+ "paddingVertical": 12,
},
undefined,
]
@@ -460,13 +543,12 @@ exports[`render unread +999 1`] = `
Object {
"alignItems": "center",
"justifyContent": "center",
- "overflow": "hidden",
},
Object {
"backgroundColor": "#3F51B5",
"borderRadius": 4,
- "height": 40,
- "width": 40,
+ "height": 46,
+ "width": 46,
},
undefined,
]
@@ -482,7 +564,7 @@ exports[`render unread +999 1`] = `
"color": "#ffffff",
},
Object {
- "fontSize": 20,
+ "fontSize": 23,
},
]
}
@@ -490,70 +572,120 @@ exports[`render unread +999 1`] = `
NA
+
-
- name
-
-
- Nov 10
-
-
-
+ name
+
+
+ Nov 10
+
+
+
- 999+
-
+ >
+
+ 999+
+
+
+
@@ -593,9 +725,11 @@ exports[`render unread 1`] = `
Array [
Object {
"alignItems": "center",
+ "borderBottomColor": "#ddd",
+ "borderBottomWidth": 0.5,
"flexDirection": "row",
"paddingHorizontal": 16,
- "paddingVertical": 10,
+ "paddingVertical": 12,
},
undefined,
]
@@ -607,13 +741,12 @@ exports[`render unread 1`] = `
Object {
"alignItems": "center",
"justifyContent": "center",
- "overflow": "hidden",
},
Object {
"backgroundColor": "#3F51B5",
"borderRadius": 4,
- "height": 40,
- "width": 40,
+ "height": 46,
+ "width": 46,
},
undefined,
]
@@ -629,7 +762,7 @@ exports[`render unread 1`] = `
"color": "#ffffff",
},
Object {
- "fontSize": 20,
+ "fontSize": 23,
},
]
}
@@ -637,70 +770,120 @@ exports[`render unread 1`] = `
NA
+
-
- name
-
-
- Nov 10
-
-
-
+ name
+
+
+ Nov 10
+
+
+
- 1
-
+ >
+
+ 1
+
+
+
@@ -740,9 +923,11 @@ exports[`renders correctly 1`] = `
Array [
Object {
"alignItems": "center",
+ "borderBottomColor": "#ddd",
+ "borderBottomWidth": 0.5,
"flexDirection": "row",
"paddingHorizontal": 16,
- "paddingVertical": 10,
+ "paddingVertical": 12,
},
undefined,
]
@@ -754,13 +939,12 @@ exports[`renders correctly 1`] = `
Object {
"alignItems": "center",
"justifyContent": "center",
- "overflow": "hidden",
},
Object {
"backgroundColor": "#3F51B5",
"borderRadius": 4,
- "height": 40,
- "width": 40,
+ "height": 46,
+ "width": 46,
},
undefined,
]
@@ -776,7 +960,7 @@ exports[`renders correctly 1`] = `
"color": "#ffffff",
},
Object {
- "fontSize": 20,
+ "fontSize": 23,
},
]
}
@@ -784,49 +968,96 @@ exports[`renders correctly 1`] = `
NA
+
-
- name
-
-
- Nov 10
-
+
+ name
+
+
+ Nov 10
+
+
+
diff --git a/__tests__/__snapshots__/Storyshots.test.js.snap b/__tests__/__snapshots__/Storyshots.test.js.snap
index 7a0a3c1b..185c7371 100644
--- a/__tests__/__snapshots__/Storyshots.test.js.snap
+++ b/__tests__/__snapshots__/Storyshots.test.js.snap
@@ -9,7 +9,6 @@ exports[`Storyshots Avatar avatar 1`] = `
Object {
"alignItems": "center",
"justifyContent": "center",
- "overflow": "hidden",
},
Object {
"backgroundColor": "#3F51B5",
@@ -46,7 +45,6 @@ exports[`Storyshots Avatar avatar 1`] = `
Object {
"alignItems": "center",
"justifyContent": "center",
- "overflow": "hidden",
},
Object {
"backgroundColor": "#9C27B0",
@@ -83,7 +81,6 @@ exports[`Storyshots Avatar avatar 1`] = `
Object {
"alignItems": "center",
"justifyContent": "center",
- "overflow": "hidden",
},
Object {
"backgroundColor": "#9C27B0",
@@ -120,7 +117,6 @@ exports[`Storyshots Avatar avatar 1`] = `
Object {
"alignItems": "center",
"justifyContent": "center",
- "overflow": "hidden",
},
Object {
"backgroundColor": "#3F51B5",
@@ -190,9 +186,11 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
Array [
Object {
"alignItems": "center",
+ "borderBottomColor": "#ddd",
+ "borderBottomWidth": 0.5,
"flexDirection": "row",
"paddingHorizontal": 16,
- "paddingVertical": 10,
+ "paddingVertical": 12,
},
undefined,
]
@@ -204,13 +202,12 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
Object {
"alignItems": "center",
"justifyContent": "center",
- "overflow": "hidden",
},
Object {
"backgroundColor": "#8BC34A",
"borderRadius": 4,
- "height": 40,
- "width": 40,
+ "height": 46,
+ "width": 46,
},
undefined,
]
@@ -226,7 +223,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
"color": "#ffffff",
},
Object {
- "fontSize": 20,
+ "fontSize": 23,
},
]
}
@@ -234,49 +231,96 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
RC
+
-
- rocket.cat
-
-
- Nov 10
-
+
+ rocket.cat
+
+
+ Nov 10
+
+
+
@@ -312,9 +356,11 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
Array [
Object {
"alignItems": "center",
+ "borderBottomColor": "#ddd",
+ "borderBottomWidth": 0.5,
"flexDirection": "row",
"paddingHorizontal": 16,
- "paddingVertical": 10,
+ "paddingVertical": 12,
},
undefined,
]
@@ -326,13 +372,12 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
Object {
"alignItems": "center",
"justifyContent": "center",
- "overflow": "hidden",
},
Object {
"backgroundColor": "#8BC34A",
"borderRadius": 4,
- "height": 40,
- "width": 40,
+ "height": 46,
+ "width": 46,
},
undefined,
]
@@ -348,7 +393,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
"color": "#ffffff",
},
Object {
- "fontSize": 20,
+ "fontSize": 23,
},
]
}
@@ -356,51 +401,98 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
RC
+
-
- rocket.cat
-
-
- Nov 10
-
+
+ rocket.cat
+
+
+ Nov 10
+
+
+
@@ -436,9 +528,11 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
Array [
Object {
"alignItems": "center",
+ "borderBottomColor": "#ddd",
+ "borderBottomWidth": 0.5,
"flexDirection": "row",
"paddingHorizontal": 16,
- "paddingVertical": 10,
+ "paddingVertical": 12,
},
undefined,
]
@@ -450,13 +544,12 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
Object {
"alignItems": "center",
"justifyContent": "center",
- "overflow": "hidden",
},
Object {
"backgroundColor": "#8BC34A",
"borderRadius": 4,
- "height": 40,
- "width": 40,
+ "height": 46,
+ "width": 46,
},
undefined,
]
@@ -472,7 +565,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
"color": "#ffffff",
},
Object {
- "fontSize": 20,
+ "fontSize": 23,
},
]
}
@@ -480,70 +573,120 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
RC
+
-
- rocket.cat
-
-
- Nov 10
-
-
-
+ rocket.cat
+
+
+ Nov 10
+
+
+
- 1
-
+ >
+
+ 1
+
+
+
+
-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
-
-
- Nov 10
-
-
-
+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
+
+
+ Nov 10
+
+
+
- 9
-
+ >
+
+ 9
+
+
+
+
-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
-
-
- Nov 10
-
-
-
+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
+
+
+ Nov 10
+
+
+
- 99
-
+ >
+
+ 99
+
+
+
+
-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
-
-
- Nov 10
-
-
-
+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
+
+
+ Nov 10
+
+
+
- 100
-
+ >
+
+ 100
+
+
+
+
-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
-
-
- Nov 10
-
-
-
+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
+
+
+ Nov 10
+
+
+
- 999+
-
+ >
+
+ 999+
+
+
+
+
-
- Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
-
-
- Nov 10
-
-
-
+ Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries
+
+
+ Nov 10
+
+
+
- @ 999+
-
+ >
+
+ @ 999+
+
+
+
+
-
- W
-
-
- Nov 10
-
+
+ W
+
+
+ Nov 10
+
+
+
@@ -1412,9 +1858,11 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
Array [
Object {
"alignItems": "center",
+ "borderBottomColor": "#ddd",
+ "borderBottomWidth": 0.5,
"flexDirection": "row",
"paddingHorizontal": 16,
- "paddingVertical": 10,
+ "paddingVertical": 12,
},
undefined,
]
@@ -1426,13 +1874,12 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
Object {
"alignItems": "center",
"justifyContent": "center",
- "overflow": "hidden",
},
Object {
"backgroundColor": "#9C27B0",
"borderRadius": 4,
- "height": 40,
- "width": 40,
+ "height": 46,
+ "width": 46,
},
undefined,
]
@@ -1448,7 +1895,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
"color": "#ffffff",
},
Object {
- "fontSize": 20,
+ "fontSize": 23,
},
]
}
@@ -1456,49 +1903,96 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
WW
+
-
- WW
-
-
- Nov 10
-
+
+ WW
+
+
+ Nov 10
+
+
+
@@ -1534,9 +2028,11 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
Array [
Object {
"alignItems": "center",
+ "borderBottomColor": "#ddd",
+ "borderBottomWidth": 0.5,
"flexDirection": "row",
"paddingHorizontal": 16,
- "paddingVertical": 10,
+ "paddingVertical": 12,
},
undefined,
]
@@ -1548,13 +2044,12 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
Object {
"alignItems": "center",
"justifyContent": "center",
- "overflow": "hidden",
},
Object {
"backgroundColor": undefined,
"borderRadius": 4,
- "height": 40,
- "width": 40,
+ "height": 46,
+ "width": 46,
},
undefined,
]
@@ -1570,7 +2065,7 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
"color": "#ffffff",
},
Object {
- "fontSize": 20,
+ "fontSize": 23,
},
]
}
@@ -1578,49 +2073,96 @@ exports[`Storyshots Channel Cell Direct Messages 1`] = `
+
-
-
-
-
- Nov 10
-
+
+
+
+
+ Nov 10
+
+
+
diff --git a/android/app/src/main/assets/fonts/Feather.ttf b/android/app/src/main/assets/fonts/Feather.ttf
new file mode 100755
index 00000000..244854c5
Binary files /dev/null and b/android/app/src/main/assets/fonts/Feather.ttf differ
diff --git a/android/app/src/main/java/com/rocketchatrn/CustomTabsAndroid.java b/android/app/src/main/java/com/rocketchatrn/CustomTabsAndroid.java
index 605a058e..e0a9db1f 100644
--- a/android/app/src/main/java/com/rocketchatrn/CustomTabsAndroid.java
+++ b/android/app/src/main/java/com/rocketchatrn/CustomTabsAndroid.java
@@ -1,4 +1,4 @@
-package com.rocketchatrn;
+package chat.rocket.reactnative;
import android.content.Intent;
import android.content.pm.ResolveInfo;
diff --git a/android/app/src/main/java/com/rocketchatrn/CustomTabsHelper.java b/android/app/src/main/java/com/rocketchatrn/CustomTabsHelper.java
index 99934ec3..b7f3eb72 100644
--- a/android/app/src/main/java/com/rocketchatrn/CustomTabsHelper.java
+++ b/android/app/src/main/java/com/rocketchatrn/CustomTabsHelper.java
@@ -1,4 +1,4 @@
-package com.rocketchatrn;
+package chat.rocket.reactnative;
import android.content.Context;
import android.content.Intent;
diff --git a/android/app/src/main/java/com/rocketchatrn/MainApplication.java b/android/app/src/main/java/com/rocketchatrn/MainApplication.java
index beb8cc02..986de10f 100644
--- a/android/app/src/main/java/com/rocketchatrn/MainApplication.java
+++ b/android/app/src/main/java/com/rocketchatrn/MainApplication.java
@@ -44,7 +44,8 @@ public class MainApplication extends Application implements ReactApplication {
new ReactVideoPackage(),
new SplashScreenReactPackage(),
new RCTToastPackage(),
- new KeyboardInputPackage(MainApplication.this)
+ new KeyboardInputPackage(MainApplication.this),
+ new RocketChatNativePackage()
);
}
};
diff --git a/android/app/src/main/java/com/rocketchatrn/RocketChatNativePackage.java b/android/app/src/main/java/com/rocketchatrn/RocketChatNativePackage.java
index bbc20f72..16cef019 100644
--- a/android/app/src/main/java/com/rocketchatrn/RocketChatNativePackage.java
+++ b/android/app/src/main/java/com/rocketchatrn/RocketChatNativePackage.java
@@ -1,4 +1,4 @@
-package com.rocketchatrn;
+package chat.rocket.reactnative;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
diff --git a/app/containers/Avatar.js b/app/containers/Avatar.js
index f547b778..3ab6c266 100644
--- a/app/containers/Avatar.js
+++ b/app/containers/Avatar.js
@@ -8,7 +8,7 @@ import avatarInitialsAndColor from '../utils/avatarInitialsAndColor';
const styles = StyleSheet.create({
iconContainer: {
- overflow: 'hidden',
+ // overflow: 'hidden',
justifyContent: 'center',
alignItems: 'center'
},
@@ -31,7 +31,8 @@ export default class Avatar extends React.PureComponent {
avatar: PropTypes.string,
size: PropTypes.number,
borderRadius: PropTypes.number,
- type: PropTypes.string
+ type: PropTypes.string,
+ children: PropTypes.object
};
render() {
const {
@@ -68,6 +69,7 @@ export default class Avatar extends React.PureComponent {
{initials}
{image}
+ {this.props.children}
);
}
diff --git a/app/containers/MessageActions.js b/app/containers/MessageActions.js
index e362c69d..6a2de4b4 100644
--- a/app/containers/MessageActions.js
+++ b/app/containers/MessageActions.js
@@ -18,6 +18,7 @@ import {
} from '../actions/messages';
import { showToast } from '../utils/info';
+const returnAnArray = obj => obj || [];
@connect(
state => ({
showActions: state.messages.showActions,
@@ -171,11 +172,11 @@ export default class MessageActions extends React.Component {
}
setPermissions(permissions) {
- this.hasEditPermission = permissions['edit-message']
+ this.hasEditPermission = returnAnArray(permissions['edit-message'])
.some(item => this.mergedRoles.indexOf(item) !== -1);
- this.hasDeletePermission = permissions['delete-message']
+ this.hasDeletePermission = returnAnArray(permissions['delete-message'])
.some(item => this.mergedRoles.indexOf(item) !== -1);
- this.hasForceDeletePermission = permissions['force-delete-message']
+ this.hasForceDeletePermission = returnAnArray(permissions['force-delete-message'])
.some(item => this.mergedRoles.indexOf(item) !== -1);
}
diff --git a/app/containers/message/Markdown.js b/app/containers/message/Markdown.js
index 805c915f..1b50f901 100644
--- a/app/containers/message/Markdown.js
+++ b/app/containers/message/Markdown.js
@@ -1,5 +1,5 @@
import React from 'react';
-import { Text, StyleSheet } from 'react-native';
+import { Text, StyleSheet, ViewPropTypes } from 'react-native';
import PropTypes from 'prop-types';
import EasyMarkdown from 'react-native-easy-markdown'; // eslint-disable-line
import SimpleMarkdown from 'simple-markdown';
@@ -17,13 +17,15 @@ const BlockCode = ({ node, state }) => (
);
const mentionStyle = { color: '#13679a' };
-const Markdown = ({ msg, customEmojis }) => {
+const Markdown = ({
+ msg, customEmojis, style, markdownStyle, customRules, renderInline
+}) => {
if (!msg) {
return null;
}
msg = emojify(msg, { output: 'unicode' });
- const rules = {
+ const defaultRules = {
username: {
order: -1,
match: SimpleMarkdown.inlineRegex(/^@[0-9a-zA-Z-_.]+/),
@@ -121,11 +123,13 @@ const Markdown = ({ msg, customEmojis }) => {
};
const codeStyle = StyleSheet.flatten(styles.codeStyle);
+ style = StyleSheet.flatten(style);
return (
{msg}
);
@@ -133,7 +137,12 @@ const Markdown = ({ msg, customEmojis }) => {
Markdown.propTypes = {
msg: PropTypes.string.isRequired,
- customEmojis: PropTypes.object
+ customEmojis: PropTypes.object,
+ // eslint-disable-next-line react/no-typos
+ style: ViewPropTypes.style,
+ markdownStyle: PropTypes.object,
+ customRules: PropTypes.object,
+ renderInline: PropTypes.bool
};
BlockCode.propTypes = {
diff --git a/app/containers/status.js b/app/containers/status.js
new file mode 100644
index 00000000..55a78fcc
--- /dev/null
+++ b/app/containers/status.js
@@ -0,0 +1,39 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import { StyleSheet, View, ViewPropTypes } from 'react-native';
+import { STATUS_COLORS } from '../constants/colors';
+
+const styles = StyleSheet.create({
+ status: {
+ borderRadius: 16,
+ width: 16,
+ height: 16
+ }
+});
+
+@connect(state => ({
+ activeUsers: state.activeUsers
+}))
+
+export default class Status extends React.Component {
+ static propTypes = {
+ style: ViewPropTypes.style,
+ id: PropTypes.string,
+ activeUsers: PropTypes.object
+ };
+
+ shouldComponentUpdate(nextProps) {
+ const userId = this.props.id;
+ return this.status !== nextProps.activeUsers[userId];
+ }
+
+ get status() {
+ const userId = this.props.id;
+ return (this.props.activeUsers && this.props.activeUsers[userId]) || 'offline';
+ }
+
+ render() {
+ return ();
+ }
+}
diff --git a/app/lib/realm.js b/app/lib/realm.js
index 14766045..bca5a7a1 100644
--- a/app/lib/realm.js
+++ b/app/lib/realm.js
@@ -49,6 +49,7 @@ const roomsSchema = {
properties: {
_id: 'string',
t: 'string',
+ lastMessage: 'messages',
_updatedAt: { type: 'date', optional: true }
}
};
@@ -80,7 +81,8 @@ const subscriptionSchema = {
// userMentions: 0,
// groupMentions: 0,
roomUpdatedAt: { type: 'date', optional: true },
- ro: { type: 'bool', optional: true }
+ ro: { type: 'bool', optional: true },
+ lastMessage: { type: 'messages', optional: true }
}
};
@@ -134,7 +136,7 @@ const attachment = {
const url = {
name: 'url',
properties: {
- _id: 'int',
+ // _id: { type: 'int', optional: true },
url: { type: 'string', optional: true },
title: { type: 'string', optional: true },
description: { type: 'string', optional: true },
@@ -183,7 +185,7 @@ const messagesSchema = {
groupable: { type: 'bool', optional: true },
avatar: { type: 'string', optional: true },
attachments: { type: 'list', objectType: 'attachment' },
- urls: { type: 'list', objectType: 'url' },
+ urls: { type: 'list', objectType: 'url', default: [] },
_updatedAt: { type: 'date', optional: true },
status: { type: 'int', optional: true },
pinned: { type: 'bool', optional: true },
diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js
index f56eb1c9..292476bb 100644
--- a/app/lib/rocketchat.js
+++ b/app/lib/rocketchat.js
@@ -128,11 +128,12 @@ const RocketChat = {
const sub = database.objects('subscriptions').filtered('rid == $0', data._id)[0];
database.write(() => {
sub.roomUpdatedAt = data._updatedAt;
+ sub.lastMessage = data.lastMessage;
sub.ro = data.ro;
});
}
});
- });
+ }).catch(console.log);
},
me({ server, token, userId }) {
@@ -428,6 +429,7 @@ const RocketChat = {
const room = rooms.find(({ _id }) => _id === subscription.rid);
if (room) {
subscription.roomUpdatedAt = room._updatedAt;
+ subscription.lastMessage = room.lastMessage;
subscription.ro = room.ro;
}
if (subscription.roles) {
@@ -435,10 +437,14 @@ const RocketChat = {
}
return subscription;
});
+
+
database.write(() => {
- data.forEach(subscription =>
- database.create('subscriptions', subscription, true));
+ data.forEach(subscription => database.create('subscriptions', subscription, true));
+ // rooms.forEach(room => database.create('rooms', room, true));
});
+
+
this.ddp.subscribe('stream-notify-user', `${ login.user.id }/subscriptions-changed`, false);
this.ddp.subscribe('stream-notify-user', `${ login.user.id }/rooms-changed`, false);
return data;
diff --git a/app/presentation/RoomItem.js b/app/presentation/RoomItem.js
index d198f91f..946796b7 100644
--- a/app/presentation/RoomItem.js
+++ b/app/presentation/RoomItem.js
@@ -2,36 +2,60 @@ import React from 'react';
import moment from 'moment';
import PropTypes from 'prop-types';
import { View, Text, StyleSheet } from 'react-native';
+
+import { connect } from 'react-redux';
+import SimpleMarkdown from 'simple-markdown';
+
import Avatar from '../containers/Avatar';
+import Status from '../containers/status';
import Touch from '../utils/touch/index'; //eslint-disable-line
+import Markdown from '../containers/message/Markdown';
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
paddingHorizontal: 16,
- paddingVertical: 10,
- alignItems: 'center'
+ paddingVertical: 12,
+ alignItems: 'center',
+ borderBottomWidth: 0.5,
+ borderBottomColor: '#ddd'
},
number: {
- minWidth: 20,
- borderRadius: 3,
+ minWidth: 25,
+ borderRadius: 4,
backgroundColor: '#1d74f5',
color: '#fff',
- textAlign: 'center',
overflow: 'hidden',
fontSize: 14,
+ paddingVertical: 4,
paddingHorizontal: 5,
- paddingVertical: 2
+
+ textAlign: 'center',
+ alignItems: 'center',
+ justifyContent: 'center'
},
roomNameView: {
flex: 1,
+ height: '100%',
marginLeft: 16,
marginRight: 4
},
roomName: {
flex: 1,
- fontSize: 16,
- color: '#444'
+ fontSize: 18,
+ color: '#444',
+
+ marginRight: 8
+ },
+ lastMessage: {
+ flex: 1,
+ flexShrink: 1,
+ marginRight: 8,
+ maxHeight: 20,
+ overflow: 'hidden',
+ flexDirection: 'row',
+ alignItems: 'flex-start',
+ justifyContent: 'flex-start'
},
alert: {
fontWeight: 'bold'
@@ -39,30 +63,144 @@ const styles = StyleSheet.create({
favorite: {
// backgroundColor: '#eee'
},
- update: {
+ row: {
+ width: '100%',
flex: 1,
+ flexDirection: 'row',
+ alignItems: 'flex-end',
+ justifyContent: 'flex-end'
+ },
+ firstRow: {
+ width: '100%',
+ flex: 1,
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ update: {
fontSize: 10,
- // height: 10,
- color: '#888'
+ color: '#888',
+ alignItems: 'center',
+ justifyContent: 'center'
+ },
+ status: {
+ position: 'absolute',
+ bottom: -3,
+ right: -3,
+ borderWidth: 3,
+ borderColor: '#fff'
}
});
+const markdownStyle = { block: { marginBottom: 0, flexWrap: 'wrap', flexDirection: 'row' } };
+const parseInline = (parse, content, state) => {
+ const isCurrentlyInline = state.inline || false;
+ state.inline = true;
+ const result = parse(content, state);
+ state.inline = isCurrentlyInline;
+ return result;
+};
+const parseCaptureInline = (capture, parse, state) => ({ content: parseInline(parse, capture[1], state) });
+const customRules = {
+ strong: {
+ order: -4,
+ match: SimpleMarkdown.inlineRegex(/^\*\*([\s\S]+?)\*\*(?!\*)/),
+ parse: parseCaptureInline,
+ react: (node, output, state) => ({
+ type: 'strong',
+ key: state.key,
+ props: {
+ children: output(node.content, state)
+ }
+ })
+ },
+ text: {
+ order: -3,
+ match: SimpleMarkdown.inlineRegex(/^[\s\S]+?(?=[^0-9A-Za-z\s\u00c0-\uffff]|\n\n| {2,}\n|\w+:\S|$)/),
+ parse: capture => ({ content: capture[0] }),
+ react: node => node.content
+ }
+};
+
+const renderNumber = (unread, userMentions) => {
+ if (!unread || unread <= 0) {
+ return;
+ }
+
+ if (unread >= 1000) {
+ unread = '999+';
+ }
+
+ if (userMentions > 0) {
+ unread = `@ ${ unread }`;
+ }
+
+ return (
+
+ { unread }
+
+ );
+};
+
+@connect(state => ({
+ user: state.login && state.login.user,
+ StoreLastMessage: state.settings.Store_Last_Message,
+ customEmojis: state.customEmojis
+}))
export default class RoomItem extends React.PureComponent {
static propTypes = {
type: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
+ StoreLastMessage: PropTypes.bool,
_updatedAt: PropTypes.instanceOf(Date),
+ lastMessage: PropTypes.object,
favorite: PropTypes.bool,
alert: PropTypes.bool,
unread: PropTypes.number,
userMentions: PropTypes.number,
- baseUrl: PropTypes.string,
- onPress: PropTypes.func
+ id: PropTypes.string,
+ onPress: PropTypes.func,
+ customEmojis: PropTypes.object,
+ user: PropTypes.object
}
get icon() {
- const { type, name, baseUrl } = this.props;
- return ;
+ const {
+ type, name, id
+ } = this.props;
+ return ({type === 'd' ? : null });
+ }
+
+ get lastMessage() {
+ const {
+ lastMessage, alert, type
+ } = this.props;
+
+ if (!this.props.StoreLastMessage) {
+ return '';
+ }
+ if (!lastMessage) {
+ return 'No Message';
+ }
+
+
+ let prefix = '';
+
+ if (lastMessage.u.username === this.props.user.username) {
+ prefix = 'You: ';
+ } else if (type !== 'd') {
+ prefix = `${ lastMessage.u.username }: `;
+ }
+
+ const msg = `${ prefix }${ lastMessage.msg.replace(/[\n\t\r]/igm, '') }`;
+
+ const maxChars = 35;
+
+
+ if (alert) {
+ return `**${ msg.slice(0, maxChars) }${ msg.replace(/:[a-z0-9]+:/gi, ':::').length > maxChars ? '...' : '' }**`;
+ }
+ return `${ msg.slice(0, maxChars) }${ msg.replace(/:[a-z0-9]+:/gi, ':::').length > maxChars ? '...' : '' }`;
}
formatDate = date => moment(date).calendar(null, {
@@ -72,29 +210,9 @@ export default class RoomItem extends React.PureComponent {
sameElse: 'MMM D'
})
- renderNumber = (unread, userMentions) => {
- if (!unread || unread <= 0) {
- return;
- }
-
- if (unread >= 1000) {
- unread = '999+';
- }
-
- if (userMentions > 0) {
- unread = `@ ${ unread }`;
- }
-
- return (
-
- { unread }
-
- );
- }
-
render() {
const {
- favorite, alert, unread, userMentions, name, _updatedAt
+ favorite, unread, userMentions, name, _updatedAt, customEmojis, alert
} = this.props;
const date = this.formatDate(_updatedAt);
@@ -117,10 +235,23 @@ export default class RoomItem extends React.PureComponent {
{this.icon}
- { name }
- {_updatedAt ? { date } : null}
+
+ { name }
+ {_updatedAt ? { date } : null}
+
+
+
+ {renderNumber(unread, userMentions)}
+
- {this.renderNumber(unread, userMentions)}
);
diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js
index 4d32ca07..ee0594d3 100644
--- a/app/views/RoomView/index.js
+++ b/app/views/RoomView/index.js
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { Text, View, Button, LayoutAnimation } from 'react-native';
+import { Text, View, Button } from 'react-native';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import equal from 'deep-equal';
@@ -51,8 +51,8 @@ export default class RoomView extends React.Component {
Message_TimeFormat: PropTypes.string,
loading: PropTypes.bool,
actionMessage: PropTypes.object,
- toggleReactionPicker: PropTypes.func.isRequired,
- layoutAnimation: PropTypes.instanceOf(Date)
+ toggleReactionPicker: PropTypes.func.isRequired
+ // layoutAnimation: PropTypes.instanceOf(Date)
};
static navigationOptions = ({ navigation }) => ({
@@ -90,11 +90,11 @@ export default class RoomView extends React.Component {
this.rooms.addListener(this.updateRoom);
}
- componentWillReceiveProps(nextProps) {
- if (this.props.layoutAnimation !== nextProps.layoutAnimation) {
- LayoutAnimation.spring();
- }
- }
+ // componentWillReceiveProps(nextProps) {
+ // // if (this.props.layoutAnimation !== nextProps.layoutAnimation) {
+ // // LayoutAnimation.spring();
+ // // }
+ // }
shouldComponentUpdate(nextProps, nextState) {
return !(equal(this.props, nextProps) && equal(this.state, nextState));
}
diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js
index f2292672..75b36c6e 100644
--- a/app/views/RoomsListView/index.js
+++ b/app/views/RoomsListView/index.js
@@ -18,6 +18,7 @@ import styles from './styles';
const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
@connect(state => ({
+ user: state.login.user,
server: state.server.server,
login: state.login,
Site_Url: state.settings.Site_Url,
@@ -31,6 +32,7 @@ const ds = new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 });
export default class RoomsListView extends React.Component {
static propTypes = {
navigation: PropTypes.object.isRequired,
+ user: PropTypes.object,
Site_Url: PropTypes.string,
server: PropTypes.string,
searchText: PropTypes.string
@@ -69,7 +71,9 @@ export default class RoomsListView extends React.Component {
this.search(props.searchText);
}
}
-
+ // componentWillUpdate() {
+ // LayoutAnimation.easeInEaseOut();
+ // }
componentWillUnmount() {
this.data.removeAllListeners();
}
@@ -79,6 +83,12 @@ export default class RoomsListView extends React.Component {
this.search(text);
}
+ getLastMessage = (subscription) => {
+ const [room] = database.objects('rooms').filtered('_id = $0', subscription.rid).slice();
+ console.log('ROOM', room);
+ return room && room.lastMessage;
+ }
+
search(text) {
const searchText = text.trim();
if (searchText === '') {
@@ -197,20 +207,23 @@ export default class RoomsListView extends React.Component {
);
- renderItem = item => (
- {
+ const id = item.rid.replace(this.props.user.id, '').trim();
+ return ( this._onPressItem(item)}
- />
- )
+ />);
+ }
renderList = () => (