From 101d4c727c6463bf5555849c229bef5de3e57649 Mon Sep 17 00:00:00 2001 From: Diego Mello Date: Tue, 4 Sep 2018 11:29:20 -0300 Subject: [PATCH] Sort/group rooms local only (#425) * Update android api from ci * Sort local only --- .circleci/config.yml | 14 ++--- app/actions/actionsTypes.js | 4 +- app/actions/sortPreferences.js | 15 +++++ app/lib/rocketchat.js | 14 +++++ app/reducers/index.js | 4 +- app/reducers/sortPreferences.js | 26 +++++++++ app/sagas/init.js | 4 ++ app/views/RoomsListView/SortDropdown.js | 46 +++++++-------- app/views/RoomsListView/index.js | 74 +++++++++++-------------- 9 files changed, 126 insertions(+), 75 deletions(-) create mode 100644 app/actions/sortPreferences.js create mode 100644 app/reducers/sortPreferences.js diff --git a/.circleci/config.yml b/.circleci/config.yml index d413ed52..0c63bf7b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -84,7 +84,7 @@ jobs: android-build: <<: *defaults docker: - - image: circleci/android:api-26-alpha + - image: circleci/android:api-27-node8-alpha environment: GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx4096m -XX:+HeapDumpOnOutOfMemoryError" @@ -95,12 +95,12 @@ jobs: steps: - checkout - - run: - name: Install Node 8 - command: | - curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.6/install.sh | bash - source ~/.nvm/nvm.sh - nvm install 8 + # - run: + # name: Install Node 8 + # command: | + # curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.6/install.sh | bash + # source ~/.nvm/nvm.sh + # nvm install 8 - restore_cache: key: node-modules-{{ checksum ".circleci/config.yml" }}-{{ checksum "package.json" }} diff --git a/app/actions/actionsTypes.js b/app/actions/actionsTypes.js index 5b8f16c9..9fc1cdc6 100644 --- a/app/actions/actionsTypes.js +++ b/app/actions/actionsTypes.js @@ -25,7 +25,8 @@ export const LOGIN = createRequestTypes('LOGIN', [ 'CLOSE', 'SET_SERVICES', 'REMOVE_SERVICES', - 'SET_PREFERENCE' + 'SET_PREFERENCE', + 'SET_SORT_PREFERENCE' ]); export const FORGOT_PASSWORD = createRequestTypes('FORGOT_PASSWORD', [ ...defaultTypes, @@ -98,6 +99,7 @@ export const MENTIONED_MESSAGES = createRequestTypes('MENTIONED_MESSAGES', ['OPE export const SNIPPETED_MESSAGES = createRequestTypes('SNIPPETED_MESSAGES', ['OPEN', 'READY', 'CLOSE', 'MESSAGES_RECEIVED']); export const ROOM_FILES = createRequestTypes('ROOM_FILES', ['OPEN', 'READY', 'CLOSE', 'MESSAGES_RECEIVED']); export const DEEP_LINKING = createRequestTypes('DEEP_LINKING', ['OPEN']); +export const SORT_PREFERENCES = createRequestTypes('SORT_PREFERENCES', ['SET_ALL', 'SET']); export const INCREMENT = 'INCREMENT'; export const DECREMENT = 'DECREMENT'; diff --git a/app/actions/sortPreferences.js b/app/actions/sortPreferences.js new file mode 100644 index 00000000..e452e74c --- /dev/null +++ b/app/actions/sortPreferences.js @@ -0,0 +1,15 @@ +import * as types from './actionsTypes'; + +export function setAllPreferences(preferences) { + return { + type: types.SORT_PREFERENCES.SET_ALL, + preferences + }; +} + +export function setPreference(preference) { + return { + type: types.SORT_PREFERENCES.SET, + preference + }; +} diff --git a/app/lib/rocketchat.js b/app/lib/rocketchat.js index 711d5d99..42b4354c 100644 --- a/app/lib/rocketchat.js +++ b/app/lib/rocketchat.js @@ -44,6 +44,7 @@ import { sendFileMessage, cancelUpload, isUploadActive } from './methods/sendFil import { getDeviceToken } from '../push'; const TOKEN_KEY = 'reactnativemeteor_usertoken'; +const SORT_PREFS_KEY = 'RC_SORT_PREFS_KEY'; const call = (method, ...params) => RocketChat.ddp.call(method, ...params); // eslint-disable-line const returnAnArray = obj => obj || []; @@ -772,6 +773,19 @@ const RocketChat = { }, setAvatarFromService({ data, contentType = '', service = null }) { return call('setAvatarFromService', data, contentType, service); + }, + async getSortPreferences() { + const prefs = await AsyncStorage.getItem(SORT_PREFS_KEY); + return JSON.parse(prefs); + }, + async saveSortPreference(param) { + try { + let prefs = await RocketChat.getSortPreferences(); + prefs = { ...prefs, ...param }; + return await AsyncStorage.setItem(SORT_PREFS_KEY, JSON.stringify(prefs)); + } catch (error) { + console.warn(error); + } } }; diff --git a/app/reducers/index.js b/app/reducers/index.js index 27d07f44..2c6c6c58 100644 --- a/app/reducers/index.js +++ b/app/reducers/index.js @@ -18,6 +18,7 @@ import pinnedMessages from './pinnedMessages'; import mentionedMessages from './mentionedMessages'; import snippetedMessages from './snippetedMessages'; import roomFiles from './roomFiles'; +import sortPreferences from './sortPreferences'; export default combineReducers({ settings, @@ -38,5 +39,6 @@ export default combineReducers({ pinnedMessages, mentionedMessages, snippetedMessages, - roomFiles + roomFiles, + sortPreferences }); diff --git a/app/reducers/sortPreferences.js b/app/reducers/sortPreferences.js new file mode 100644 index 00000000..d5cd2ba3 --- /dev/null +++ b/app/reducers/sortPreferences.js @@ -0,0 +1,26 @@ +import { SORT_PREFERENCES } from '../actions/actionsTypes'; + +const initialState = { + sortBy: 'activity', + groupByType: true, + showFavorites: true, + showUnread: true +}; + + +export default (state = initialState, action) => { + switch (action.type) { + case SORT_PREFERENCES.SET_ALL: + return { + ...state, + ...action.preferences + }; + case SORT_PREFERENCES.SET: + return { + ...state, + ...action.preference + }; + default: + return state; + } +}; diff --git a/app/sagas/init.js b/app/sagas/init.js index 5eabde10..8ed38b4f 100644 --- a/app/sagas/init.js +++ b/app/sagas/init.js @@ -4,6 +4,7 @@ import { call, put, takeLatest } from 'redux-saga/effects'; import * as actions from '../actions'; import { selectServerRequest } from '../actions/server'; import { restoreToken, setUser } from '../actions/login'; +import { setAllPreferences } from '../actions/sortPreferences'; import { APP } from '../actions/actionsTypes'; import RocketChat from '../lib/rocketchat'; import log from '../utils/log'; @@ -27,6 +28,9 @@ const restore = function* restore() { } } + const sortPreferences = yield RocketChat.getSortPreferences(); + yield put(setAllPreferences(sortPreferences)); + yield put(actions.appReady({})); } catch (e) { log('restore', e); diff --git a/app/views/RoomsListView/SortDropdown.js b/app/views/RoomsListView/SortDropdown.js index 5ecc37c9..b2b8718f 100644 --- a/app/views/RoomsListView/SortDropdown.js +++ b/app/views/RoomsListView/SortDropdown.js @@ -6,7 +6,7 @@ import { connect } from 'react-redux'; import Touch from '../../utils/touch'; import styles from './styles'; import RocketChat from '../../lib/rocketchat'; -import { setPreference } from '../../actions/login'; +import { setPreference } from '../../actions/sortPreferences'; import log from '../../utils/log'; import I18n from '../../i18n'; @@ -15,17 +15,17 @@ const ANIMATION_DURATION = 200; @connect(state => ({ closeSortDropdown: state.rooms.closeSortDropdown }), dispatch => ({ - setPreference: preference => dispatch(setPreference(preference)) + setSortPreference: preference => dispatch(setPreference(preference)) })) export default class Sort extends Component { static propTypes = { closeSortDropdown: PropTypes.bool, close: PropTypes.func, - sidebarSortby: PropTypes.string, - sidebarGroupByType: PropTypes.bool, - sidebarShowFavorites: PropTypes.bool, - sidebarShowUnread: PropTypes.bool, - setPreference: PropTypes.func + sortBy: PropTypes.string, + groupByType: PropTypes.bool, + showFavorites: PropTypes.bool, + showUnread: PropTypes.bool, + setSortPreference: PropTypes.func } constructor(props) { @@ -51,33 +51,33 @@ export default class Sort extends Component { } } - saveUserPreference = async(param) => { + setSortPreference = async(param) => { try { - this.props.setPreference(param); - await RocketChat.saveUserPreferences(param); + this.props.setSortPreference(param); + RocketChat.saveSortPreference(param); } catch (e) { - log('RoomsListView.saveUserPreference', e); + log('RoomsListView.setSortPreference', e); } } sortByName = () => { - this.saveUserPreference({ sidebarSortby: 'alphabetical' }); + this.setSortPreference({ sortBy: 'alphabetical' }); } sortByActivity = () => { - this.saveUserPreference({ sidebarSortby: 'activity' }); + this.setSortPreference({ sortBy: 'activity' }); } toggleGroupByType = () => { - this.saveUserPreference({ sidebarGroupByType: !this.props.sidebarGroupByType }); + this.setSortPreference({ groupByType: !this.props.groupByType }); } toggleGroupByFavorites = () => { - this.saveUserPreference({ sidebarShowFavorites: !this.props.sidebarShowFavorites }); + this.setSortPreference({ showFavorites: !this.props.showFavorites }); } toggleUnread = () => { - this.saveUserPreference({ sidebarShowUnread: !this.props.sidebarShowUnread }); + this.setSortPreference({ showUnread: !this.props.showUnread }); } close = () => { @@ -102,7 +102,7 @@ export default class Sort extends Component { outputRange: [0, 0.3] }); const { - sidebarSortby, sidebarGroupByType, sidebarShowFavorites, sidebarShowUnread + sortBy, groupByType, showFavorites, showUnread } = this.props; return ( [ @@ -117,14 +117,14 @@ export default class Sort extends Component { {I18n.t('Alphabetical')} - {sidebarSortby === 'alphabetical' ? : null} + {sortBy === 'alphabetical' ? : null} {I18n.t('Activity')} - {sidebarSortby === 'activity' ? : null} + {sortBy === 'activity' ? : null} @@ -132,21 +132,21 @@ export default class Sort extends Component { {I18n.t('Group_by_type')} - {sidebarGroupByType ? : null} + {groupByType ? : null} {I18n.t('Group_by_favorites')} - {sidebarShowFavorites ? : null} + {showFavorites ? : null} {I18n.t('Unread_on_top')} - {sidebarShowUnread ? : null} + {showUnread ? : null} , @@ -156,7 +156,7 @@ export default class Sort extends Component { style={[styles.dropdownContainerHeader, styles.sortToggleContainerClose]} > - {I18n.t('Sorting_by', { key: I18n.t(this.props.sidebarSortby === 'alphabetical' ? 'name' : 'activity') })} + {I18n.t('Sorting_by', { key: I18n.t(this.props.sortBy === 'alphabetical' ? 'name' : 'activity') })} diff --git a/app/views/RoomsListView/index.js b/app/views/RoomsListView/index.js index bc11cacf..608e7d1e 100644 --- a/app/views/RoomsListView/index.js +++ b/app/views/RoomsListView/index.js @@ -39,31 +39,19 @@ if (Platform.OS === 'android') { }); } -@connect((state) => { - let result = { - userId: state.login.user && state.login.user.id, - server: state.server.server, - Site_Url: state.settings.Site_Url, - searchText: state.rooms.searchText, - loadingServer: state.server.loading, - showServerDropdown: state.rooms.showServerDropdown, - showSortDropdown: state.rooms.showSortDropdown, - sidebarSortby: null, - sidebarGroupByType: null, - sidebarShowFavorites: null, - sidebarShowUnread: null - }; - if (state.login && state.login.user && state.login.user.settings && state.login.user.settings.preferences) { - result = { - ...result, - sidebarSortby: state.login.user.settings.preferences.sidebarSortby, - sidebarGroupByType: state.login.user.settings.preferences.sidebarGroupByType, - sidebarShowFavorites: state.login.user.settings.preferences.sidebarShowFavorites, - sidebarShowUnread: state.login.user.settings.preferences.sidebarShowUnread - }; - } - return result; -}, dispatch => ({ +@connect(state => ({ + userId: state.login.user && state.login.user.id, + server: state.server.server, + Site_Url: state.settings.Site_Url, + searchText: state.rooms.searchText, + loadingServer: state.server.loading, + showServerDropdown: state.rooms.showServerDropdown, + showSortDropdown: state.rooms.showSortDropdown, + sortBy: state.sortPreferences.sortBy, + groupByType: state.sortPreferences.groupByType, + showFavorites: state.sortPreferences.showFavorites, + showUnread: state.sortPreferences.showUnread +}), dispatch => ({ toggleSortDropdown: () => dispatch(toggleSortDropdown()) })) /** @extends React.Component */ @@ -88,10 +76,10 @@ export default class RoomsListView extends LoggedView { loadingServer: PropTypes.bool, showServerDropdown: PropTypes.bool, showSortDropdown: PropTypes.bool, - sidebarSortby: PropTypes.string, - sidebarGroupByType: PropTypes.bool, - sidebarShowFavorites: PropTypes.bool, - sidebarShowUnread: PropTypes.bool, + sortBy: PropTypes.string, + groupByType: PropTypes.bool, + showFavorites: PropTypes.bool, + showUnread: PropTypes.bool, toggleSortDropdown: PropTypes.func } @@ -138,10 +126,10 @@ export default class RoomsListView extends LoggedView { componentDidUpdate(prevProps) { if (!( - (prevProps.sidebarSortby === this.props.sidebarSortby) && - (prevProps.sidebarGroupByType === this.props.sidebarGroupByType) && - (prevProps.sidebarShowFavorites === this.props.sidebarShowFavorites) && - (prevProps.sidebarShowUnread === this.props.sidebarShowUnread) + (prevProps.sortBy === this.props.sortBy) && + (prevProps.groupByType === this.props.groupByType) && + (prevProps.showFavorites === this.props.showFavorites) && + (prevProps.showUnread === this.props.showUnread) )) { this.getSubscriptions(); } @@ -195,7 +183,7 @@ export default class RoomsListView extends LoggedView { getSubscriptions = () => { if (this.props.server && this.hasActiveDB()) { - if (this.props.sidebarSortby === 'alphabetical') { + if (this.props.sortBy === 'alphabetical') { this.data = database.objects('subscriptions').filtered('archived != true && open == true').sorted('name', false); } else { this.data = database.objects('subscriptions').filtered('archived != true && open == true').sorted('roomUpdatedAt', true); @@ -210,7 +198,7 @@ export default class RoomsListView extends LoggedView { let livechat = []; // unread - if (this.props.sidebarShowUnread) { + if (this.props.showUnread) { this.unread = this.data.filtered('archived != true && open == true').sorted('name', false).filtered('(unread > 0 || alert == true)'); unread = this.unread.slice(); setTimeout(() => { @@ -220,7 +208,7 @@ export default class RoomsListView extends LoggedView { this.removeListener(unread); } // favorites - if (this.props.sidebarShowFavorites) { + if (this.props.showFavorites) { this.favorites = this.data.filtered('f == true'); favorites = this.favorites.slice(); setTimeout(() => { @@ -230,7 +218,7 @@ export default class RoomsListView extends LoggedView { this.removeListener(favorites); } // type - if (this.props.sidebarGroupByType) { + if (this.props.groupByType) { // channels this.channels = this.data.filtered('t == $0', 'c'); channels = this.channels.slice(); @@ -382,7 +370,7 @@ export default class RoomsListView extends LoggedView { style={styles.dropdownContainerHeader} > - {I18n.t('Sorting_by', { key: I18n.t(this.props.sidebarSortby === 'alphabetical' ? 'name' : 'activity') })} + {I18n.t('Sorting_by', { key: I18n.t(this.props.sortBy === 'alphabetical' ? 'name' : 'activity') })} @@ -496,7 +484,7 @@ export default class RoomsListView extends LoggedView { render = () => { const { - sidebarSortby, sidebarGroupByType, sidebarShowFavorites, sidebarShowUnread, showServerDropdown, showSortDropdown + sortBy, groupByType, showFavorites, showUnread, showServerDropdown, showSortDropdown } = this.props; return ( @@ -505,10 +493,10 @@ export default class RoomsListView extends LoggedView { {showSortDropdown ? : null} {showServerDropdown ? : null}