Skip to content

Commit

Permalink
Room actions (#231)
Browse files Browse the repository at this point in the history
* Layout


* Empty starred list


* Favorite room

* Pinned messages

* fix last messages

* fix date on pinned messages
  • Loading branch information
diegolmello authored and ggazzo committed Feb 19, 2018
1 parent bb5e29f commit b1bb815
Show file tree
Hide file tree
Showing 24 changed files with 739 additions and 25 deletions.
4 changes: 2 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ jobs:
- image: circleci/android:api-26-alpha

environment:
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError"
JVM_OPTS: -Xmx2048m
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError"
JVM_OPTS: -Xmx4096m
TERM: dumb
BASH_ENV: "~/.nvm/nvm.sh"

Expand Down
2 changes: 2 additions & 0 deletions app/actions/actionsTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ export const SERVER = createRequestTypes('SERVER', [
export const METEOR = createRequestTypes('METEOR_CONNECT', [...defaultTypes, 'DISCONNECT', 'DISCONNECT_BY_USER']);
export const LOGOUT = 'LOGOUT'; // logout is always success
export const ACTIVE_USERS = createRequestTypes('ACTIVE_USERS', ['SET', 'REQUEST']);
export const STARRED_MESSAGES = createRequestTypes('STARRED_MESSAGES', ['OPEN', 'CLOSE', 'MESSAGE_RECEIVED', 'MESSAGE_UNSTARRED']);
export const PINNED_MESSAGES = createRequestTypes('PINNED_MESSAGES', ['OPEN', 'CLOSE', 'MESSAGE_RECEIVED', 'MESSAGE_UNPINNED']);

export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
Expand Down
28 changes: 28 additions & 0 deletions app/actions/pinnedMessages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as types from './actionsTypes';

export function openPinnedMessages(rid) {
return {
type: types.PINNED_MESSAGES.OPEN,
rid
};
}

export function closePinnedMessages() {
return {
type: types.PINNED_MESSAGES.CLOSE
};
}

export function pinnedMessageReceived(message) {
return {
type: types.PINNED_MESSAGES.MESSAGE_RECEIVED,
message
};
}

export function pinnedMessageUnpinned(messageId) {
return {
type: types.PINNED_MESSAGES.MESSAGE_UNPINNED,
messageId
};
}
28 changes: 28 additions & 0 deletions app/actions/starredMessages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as types from './actionsTypes';

export function openStarredMessages(rid) {
return {
type: types.STARRED_MESSAGES.OPEN,
rid
};
}

export function closeStarredMessages() {
return {
type: types.STARRED_MESSAGES.CLOSE
};
}

export function starredMessageReceived(message) {
return {
type: types.STARRED_MESSAGES.MESSAGE_RECEIVED,
message
};
}

export function starredMessageUnstarred(messageId) {
return {
type: types.STARRED_MESSAGES.MESSAGE_UNSTARRED,
messageId
};
}
15 changes: 8 additions & 7 deletions app/containers/message/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import { View, TouchableHighlight, Text, TouchableOpacity, Vibration } from 'react-native';
import { View, TouchableHighlight, Text, TouchableOpacity, Vibration, ViewPropTypes } from 'react-native';
import { connect } from 'react-redux';
import Icon from 'react-native-vector-icons/MaterialIcons';
import moment from 'moment';
Expand Down Expand Up @@ -33,17 +33,18 @@ import styles from './styles';
export default class Message extends React.Component {
static propTypes = {
item: PropTypes.object.isRequired,
reactions: PropTypes.object.isRequired,
reactions: PropTypes.any.isRequired,
baseUrl: PropTypes.string.isRequired,
Message_TimeFormat: PropTypes.string.isRequired,
message: PropTypes.object.isRequired,
user: PropTypes.object.isRequired,
editing: PropTypes.bool,
actionsShow: PropTypes.func,
errorActionsShow: PropTypes.func,
customEmojis: PropTypes.object,
toggleReactionPicker: PropTypes.func,
onReactionPress: PropTypes.func
onReactionPress: PropTypes.func,
style: ViewPropTypes.style,
onLongPress: PropTypes.func
}

constructor(props) {
Expand Down Expand Up @@ -73,7 +74,7 @@ export default class Message extends React.Component {
}

onLongPress() {
this.props.actionsShow(this.parseMessage());
this.props.onLongPress(this.parseMessage());
}

onErrorPress() {
Expand Down Expand Up @@ -222,7 +223,7 @@ export default class Message extends React.Component {

render() {
const {
item, message, editing, baseUrl, customEmojis
item, message, editing, baseUrl, customEmojis, style
} = this.props;
const username = item.alias || item.u.username;
const isEditing = message._id === item._id && editing;
Expand All @@ -235,7 +236,7 @@ export default class Message extends React.Component {
disabled={this.isDeleted() || this.hasError()}
underlayColor='#FFFFFF'
activeOpacity={0.3}
style={[styles.message, isEditing ? styles.editing : null]}
style={[styles.message, isEditing ? styles.editing : null, style]}
accessibilityLabel={accessibilityLabel}
>
<View style={styles.flex}>
Expand Down
24 changes: 24 additions & 0 deletions app/containers/routes/AuthRoutes.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import { StackNavigator, DrawerNavigator } from 'react-navigation';
import Sidebar from '../../containers/Sidebar';
import RoomsListView from '../../views/RoomsListView';
import RoomView from '../../views/RoomView';
import RoomActionsView from '../../views/RoomActionsView';
import CreateChannelView from '../../views/CreateChannelView';
import SelectUsersView from '../../views/SelectUsersView';
import NewServerView from '../../views/NewServerView';
import StarredMessagesView from '../../views/StarredMessagesView';
import PinnedMessagesView from '../../views/PinnedMessagesView';

const AuthRoutes = StackNavigator(
{
Expand All @@ -33,6 +36,27 @@ const AuthRoutes = StackNavigator(
navigationOptions: {
title: 'New server'
}
},
RoomActions: {
screen: RoomActionsView,
navigationOptions: {
title: 'Actions',
headerTintColor: '#292E35'
}
},
StarredMessages: {
screen: StarredMessagesView,
navigationOptions: {
title: 'Starred Messages',
headerTintColor: '#292E35'
}
},
PinnedMessages: {
screen: PinnedMessagesView,
navigationOptions: {
title: 'Pinned Messages',
headerTintColor: '#292E35'
}
}
},
{
Expand Down
7 changes: 4 additions & 3 deletions app/lib/createStore.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createStore, applyMiddleware } from 'redux';
import { createStore, applyMiddleware, compose } from 'redux';
import createSagaMiddleware from 'redux-saga';
import logger from 'redux-logger';
import { composeWithDevTools } from 'remote-redux-devtools';
Expand All @@ -13,14 +13,15 @@ if (__DEV__) {
/* eslint-disable global-require */
const reduxImmutableStateInvariant = require('redux-immutable-state-invariant').default();

enhacers = composeWithDevTools(
const devComposer = composeWithDevTools({ hostname: 'localhost', port: 8000 });
enhacers = devComposer(
applyAppStateListener(),
applyMiddleware(reduxImmutableStateInvariant),
applyMiddleware(sagaMiddleware),
applyMiddleware(logger)
);
} else {
enhacers = composeWithDevTools(
enhacers = compose(
applyAppStateListener(),
applyMiddleware(sagaMiddleware)
);
Expand Down
1 change: 1 addition & 0 deletions app/lib/realm.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ const subscriptionSchema = {
// groupMentions: 0,
roomUpdatedAt: { type: 'date', optional: true },
ro: { type: 'bool', optional: true },
lastOpen: { type: 'date', optional: true },
lastMessage: { type: 'messages', optional: true }
}
};
Expand Down
44 changes: 39 additions & 5 deletions app/lib/rocketchat.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { someoneTyping, roomMessageReceived } from '../actions/room';
import { setUser } from '../actions/login';
import { disconnect, disconnect_by_user, connectSuccess, connectFailure } from '../actions/connect';
import { requestActiveUser } from '../actions/activeUsers';
import { starredMessageReceived, starredMessageUnstarred } from '../actions/starredMessages';
import { pinnedMessageReceived, pinnedMessageUnpinned } from '../actions/pinnedMessages';
import Ddp from './ddp';

export { Accounts } from 'react-native-meteor';
Expand Down Expand Up @@ -145,6 +147,30 @@ const RocketChat = {
});
}
});

this.ddp.on('rocketchat_starred_message', (ddpMessage) => {
if (ddpMessage.msg === 'added') {
const message = ddpMessage.fields;
message._id = ddpMessage.id;
const starredMessage = this._buildMessage(message);
return reduxStore.dispatch(starredMessageReceived(starredMessage));
}
if (ddpMessage.msg === 'removed') {
return reduxStore.dispatch(starredMessageUnstarred(ddpMessage.id));
}
});

this.ddp.on('rocketchat_pinned_message', (ddpMessage) => {
if (ddpMessage.msg === 'added') {
const message = ddpMessage.fields;
message._id = ddpMessage.id;
const pinnedMessage = this._buildMessage(message);
return reduxStore.dispatch(pinnedMessageReceived(pinnedMessage));
}
if (ddpMessage.msg === 'removed') {
return reduxStore.dispatch(pinnedMessageUnpinned(ddpMessage.id));
}
});
}).catch(console.log);
},

Expand Down Expand Up @@ -272,9 +298,7 @@ const RocketChat = {
_buildMessage(message) {
message.status = messagesStatus.SENT;
normalizeMessage(message);
if (message.urls) {
message.urls = RocketChat._parseUrls(message.urls);
}
message.urls = message.urls ? RocketChat._parseUrls(message.urls) : [];
// loadHistory returns message.starred as object
// stream-room-messages returns message.starred as an array
message.starred = message.starred && (Array.isArray(message.starred) ? message.starred.length > 0 : !!message.starred);
Expand Down Expand Up @@ -358,8 +382,15 @@ const RocketChat = {
createDirectMessage(username) {
return call('createDirectMessage', username);
},
readMessages(rid) {
return call('readMessages', rid);
async readMessages(rid) {
const ret = await call('readMessages', rid);

const [subscription] = database.objects('subscriptions').filtered('rid = $0', rid);
database.write(() => {
subscription.lastOpen = new Date();
});

return ret;
},
joinRoom(rid) {
return call('joinRoom', rid);
Expand Down Expand Up @@ -610,6 +641,9 @@ const RocketChat = {
},
setReaction(emoji, messageId) {
return call('setReaction', emoji, messageId);
},
toggleFavorite(rid, f) {
return call('toggleFavorite', rid, !f);
}
};

Expand Down
6 changes: 5 additions & 1 deletion app/reducers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import app from './app';
import permissions from './permissions';
import customEmojis from './customEmojis';
import activeUsers from './activeUsers';
import starredMessages from './starredMessages';
import pinnedMessages from './pinnedMessages';

export default combineReducers({
settings,
Expand All @@ -26,5 +28,7 @@ export default combineReducers({
rooms,
permissions,
customEmojis,
activeUsers
activeUsers,
starredMessages,
pinnedMessages
});
24 changes: 24 additions & 0 deletions app/reducers/pinnedMessages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { PINNED_MESSAGES } from '../actions/actionsTypes';

const initialState = {
messages: []
};

export default function server(state = initialState, action) {
switch (action.type) {
case PINNED_MESSAGES.MESSAGE_RECEIVED:
return {
...state,
messages: [...state.messages, action.message]
};
case PINNED_MESSAGES.MESSAGE_UNPINNED:
return {
...state,
messages: state.messages.filter(message => message._id !== action.messageId)
};
case PINNED_MESSAGES.CLOSE:
return initialState;
default:
return state;
}
}
24 changes: 24 additions & 0 deletions app/reducers/starredMessages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { STARRED_MESSAGES } from '../actions/actionsTypes';

const initialState = {
messages: []
};

export default function server(state = initialState, action) {
switch (action.type) {
case STARRED_MESSAGES.MESSAGE_RECEIVED:
return {
...state,
messages: [...state.messages, action.message]
};
case STARRED_MESSAGES.MESSAGE_UNSTARRED:
return {
...state,
messages: state.messages.filter(message => message._id !== action.messageId)
};
case STARRED_MESSAGES.CLOSE:
return initialState;
default:
return state;
}
}
6 changes: 5 additions & 1 deletion app/sagas/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import createChannel from './createChannel';
import init from './init';
import state from './state';
import activeUsers from './activeUsers';
import starredMessages from './starredMessages';
import pinnedMessages from './pinnedMessages';

const root = function* root() {
yield all([
Expand All @@ -21,7 +23,9 @@ const root = function* root() {
messages(),
selectServer(),
state(),
activeUsers()
activeUsers(),
starredMessages(),
pinnedMessages()
]);
};

Expand Down
14 changes: 14 additions & 0 deletions app/sagas/pinnedMessages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { take, takeLatest } from 'redux-saga/effects';
import * as types from '../actions/actionsTypes';
import RocketChat from '../lib/rocketchat';

const watchPinnedMessagesRoom = function* watchPinnedMessagesRoom({ rid }) {
const sub = yield RocketChat.subscribe('pinnedMessages', rid, 50);
yield take(types.PINNED_MESSAGES.CLOSE);
sub.unsubscribe().catch(e => alert(e));
};

const root = function* root() {
yield takeLatest(types.PINNED_MESSAGES.OPEN, watchPinnedMessagesRoom);
};
export default root;
Loading

0 comments on commit b1bb815

Please sign in to comment.