diff --git a/app/containers/UIKit/MultiSelect/Chips.js b/app/containers/UIKit/MultiSelect/Chips.js
index 330a04d8f..dae9c797e 100644
--- a/app/containers/UIKit/MultiSelect/Chips.js
+++ b/app/containers/UIKit/MultiSelect/Chips.js
@@ -20,7 +20,7 @@ const Chip = ({ item, onSelect, theme }) => (
>
<>
{item.imageUrl ? : null}
- {textParser([item.text])}
+ {textParser([item.text])}
>
diff --git a/app/containers/UIKit/MultiSelect/index.js b/app/containers/UIKit/MultiSelect/index.js
index 47e6141b4..553e92c61 100644
--- a/app/containers/UIKit/MultiSelect/index.js
+++ b/app/containers/UIKit/MultiSelect/index.js
@@ -41,6 +41,12 @@ export const MultiSelect = React.memo(({
const [currentValue, setCurrentValue] = useState('');
const [showContent, setShowContent] = useState(false);
+ useEffect(() => {
+ if (values) {
+ select(values);
+ }
+ }, [values]);
+
useEffect(() => {
setOpen(showContent);
}, [showContent]);
diff --git a/app/containers/UIKit/MultiSelect/styles.js b/app/containers/UIKit/MultiSelect/styles.js
index f0034364a..bac42a168 100644
--- a/app/containers/UIKit/MultiSelect/styles.js
+++ b/app/containers/UIKit/MultiSelect/styles.js
@@ -34,6 +34,7 @@ export default StyleSheet.create({
},
item: {
height: 48,
+ maxWidth: '85%',
alignItems: 'center',
flexDirection: 'row'
},
@@ -59,7 +60,7 @@ export default StyleSheet.create({
chips: {
flexDirection: 'row',
flexWrap: 'wrap',
- marginRight: 16
+ marginRight: 50
},
chip: {
flexDirection: 'row',
@@ -72,6 +73,7 @@ export default StyleSheet.create({
},
chipText: {
paddingHorizontal: 8,
+ flexShrink: 1,
...sharedStyles.textMedium,
fontSize: 14
},
diff --git a/app/i18n/locales/en.js b/app/i18n/locales/en.js
index d5cf54295..f632e7b8d 100644
--- a/app/i18n/locales/en.js
+++ b/app/i18n/locales/en.js
@@ -210,6 +210,21 @@ export default {
Has_joined_the_channel: 'Has joined the channel',
Has_joined_the_conversation: 'Has joined the conversation',
Has_left_the_channel: 'Has left the channel',
+ Hide_System_Messages: 'Hide System Messages',
+ Hide_type_messages: 'Hide "{{type}}" messages',
+ Message_HideType_uj: 'User Join',
+ Message_HideType_ul: 'User Leave',
+ Message_HideType_ru: 'User Removed',
+ Message_HideType_au: 'User Added',
+ Message_HideType_mute_unmute: 'User Muted / Unmuted',
+ Message_HideType_r: 'Room Name Changed',
+ Message_HideType_ut: 'User Joined Conversation',
+ Message_HideType_wm: 'Welcome',
+ Message_HideType_rm: 'Message Removed',
+ Message_HideType_subscription_role_added: 'Was Set Role',
+ Message_HideType_subscription_role_removed: 'Role No Longer Defined',
+ Message_HideType_room_archived: 'Room Archived',
+ Message_HideType_room_unarchived: 'Room Unarchived',
In_app: 'In-app',
IN_APP_AND_DESKTOP: 'IN-APP AND DESKTOP',
In_App_and_Desktop_Alert_info: 'Displays a banner at the top of the screen when app is open, and displays a notification on desktop',
@@ -295,6 +310,7 @@ export default {
Only_authorized_users_can_write_new_messages: 'Only authorized users can write new messages',
Open_emoji_selector: 'Open emoji selector',
Open_Source_Communication: 'Open Source Communication',
+ Overwrites_the_server_configuration_and_use_room_config: 'Overwrites the server configuration and use room config',
Password: 'Password',
Permalink_copied_to_clipboard: 'Permalink copied to clipboard!',
Pin: 'Pin',
@@ -454,6 +470,7 @@ export default {
Username_is_empty: 'Username is empty',
Username: 'Username',
Username_or_email: 'Username or email',
+ Uses_server_configuration: 'Uses server configuration',
Validating: 'Validating',
Verify_email_title: 'Registration Succeeded!',
Verify_email_desc: 'We have sent you an email to confirm your registration. If you do not receive an email shortly, please come back and try again.',
diff --git a/app/i18n/locales/pt-BR.js b/app/i18n/locales/pt-BR.js
index a10a770c2..bee747f8d 100644
--- a/app/i18n/locales/pt-BR.js
+++ b/app/i18n/locales/pt-BR.js
@@ -201,6 +201,21 @@ export default {
Has_joined_the_channel: 'Entrou no canal',
Has_joined_the_conversation: 'Entrou na conversa',
Has_left_the_channel: 'Saiu da conversa',
+ Hide_System_Messages: 'Esconder mensagens do sistema',
+ Hide_type_messages: 'Esconder mensagens de "{{type}}"',
+ Message_HideType_uj: 'Utilizador Entrou',
+ Message_HideType_ul: 'Utilizador Saiu',
+ Message_HideType_ru: 'Utilizador Removido',
+ Message_HideType_au: 'Utilizador adicionado',
+ Message_HideType_mute_unmute: 'Utilizador Silenciado',
+ Message_HideType_r: 'Nome da sala alterado',
+ Message_HideType_ut: 'Utilizador adicionado ao bate-papo',
+ Message_HideType_wm: 'Bem Vindo',
+ Message_HideType_rm: 'Mensagem Removida',
+ Message_HideType_subscription_role_added: 'Papel atribuído',
+ Message_HideType_subscription_role_removed: 'Papel removido',
+ Message_HideType_room_archived: 'Sala arquivada',
+ Message_HideType_room_unarchived: 'Sala desarquivada',
In_app: 'No app',
Invisible: 'Invisível',
Invite: 'Convidar',
@@ -271,6 +286,7 @@ export default {
Only_authorized_users_can_write_new_messages: 'Somente usuários autorizados podem escrever novas mensagens',
Open_emoji_selector: 'Abrir seletor de emoji',
Open_Source_Communication: 'Comunicação Open Source',
+ Overwrites_the_server_configuration_and_use_room_config: 'Substituir a configuração do servidor e usar a configuração da sala',
Password: 'Senha',
Permalink_copied_to_clipboard: 'Link-permanente copiado para a área de transferência!',
Pin: 'Fixar',
@@ -409,6 +425,7 @@ export default {
Username_is_empty: 'Usuário está vazio',
Username: 'Usuário',
Username_or_email: 'Usuário ou email',
+ Uses_server_configuration: 'Usar configuração do servidor',
Verify_email_title: 'Registrado com sucesso!',
Verify_email_desc: 'Nós lhe enviamos um e-mail para confirmar o seu registro. Se você não receber um e-mail em breve, por favor retorne e tente novamente.',
Video_call: 'Chamada de vídeo',
diff --git a/app/lib/database/model/Subscription.js b/app/lib/database/model/Subscription.js
index 630c640b3..d40193c52 100644
--- a/app/lib/database/model/Subscription.js
+++ b/app/lib/database/model/Subscription.js
@@ -89,4 +89,6 @@ export default class Subscription extends Model {
@children('thread_messages') threadMessages;
@field('hide_unread_status') hideUnreadStatus;
+
+ @json('sys_mes', sanitizer) sysMes;
}
diff --git a/app/lib/database/model/migrations.js b/app/lib/database/model/migrations.js
index ced859bda..14313585e 100644
--- a/app/lib/database/model/migrations.js
+++ b/app/lib/database/model/migrations.js
@@ -51,6 +51,17 @@ export default schemaMigrations({
]
})
]
+ },
+ {
+ toVersion: 6,
+ steps: [
+ addColumns({
+ table: 'subscriptions',
+ columns: [
+ { name: 'sys_mes', type: 'string', isOptional: true }
+ ]
+ })
+ ]
}
]
});
diff --git a/app/lib/database/schema/app.js b/app/lib/database/schema/app.js
index de98df29b..20741b573 100644
--- a/app/lib/database/schema/app.js
+++ b/app/lib/database/schema/app.js
@@ -1,7 +1,7 @@
import { appSchema, tableSchema } from '@nozbe/watermelondb';
export default appSchema({
- version: 5,
+ version: 6,
tables: [
tableSchema({
name: 'subscriptions',
@@ -39,7 +39,8 @@ export default appSchema({
{ name: 'jitsi_timeout', type: 'number', isOptional: true },
{ name: 'auto_translate', type: 'boolean', isOptional: true },
{ name: 'auto_translate_language', type: 'string' },
- { name: 'hide_unread_status', type: 'boolean', isOptional: true }
+ { name: 'hide_unread_status', type: 'boolean', isOptional: true },
+ { name: 'sys_mes', type: 'string', isOptional: true }
]
}),
tableSchema({
diff --git a/app/lib/methods/helpers/mergeSubscriptionsRooms.js b/app/lib/methods/helpers/mergeSubscriptionsRooms.js
index 02a7a6612..6af040f5b 100644
--- a/app/lib/methods/helpers/mergeSubscriptionsRooms.js
+++ b/app/lib/methods/helpers/mergeSubscriptionsRooms.js
@@ -32,6 +32,7 @@ export const merge = (subscription, room) => {
} else {
subscription.muted = [];
}
+ subscription.sysMes = room.sysMes;
}
if (!subscription.name) {
diff --git a/app/utils/messageTypes.js b/app/utils/messageTypes.js
new file mode 100644
index 000000000..f874a437a
--- /dev/null
+++ b/app/utils/messageTypes.js
@@ -0,0 +1,42 @@
+export const MessageTypeValues = [
+ {
+ value: 'uj',
+ text: 'Message_HideType_uj'
+ }, {
+ value: 'ul',
+ text: 'Message_HideType_ul'
+ }, {
+ value: 'ru',
+ text: 'Message_HideType_ru'
+ }, {
+ value: 'au',
+ text: 'Message_HideType_au'
+ }, {
+ value: 'mute_unmute',
+ text: 'Message_HideType_mute_unmute'
+ }, {
+ value: 'r',
+ text: 'Message_HideType_r'
+ }, {
+ value: 'ut',
+ text: 'Message_HideType_ut'
+ }, {
+ value: 'wm',
+ text: 'Message_HideType_wm'
+ }, {
+ value: 'rm',
+ text: 'Message_HideType_rm'
+ }, {
+ value: 'subscription_role_added',
+ text: 'Message_HideType_subscription_role_added'
+ }, {
+ value: 'subscription_role_removed',
+ text: 'Message_HideType_subscription_role_removed'
+ }, {
+ value: 'room_archived',
+ text: 'Message_HideType_room_archived'
+ }, {
+ value: 'room_unarchived',
+ text: 'Message_HideType_room_unarchived'
+ }
+];
diff --git a/app/views/RoomInfoEditView/SwitchContainer.js b/app/views/RoomInfoEditView/SwitchContainer.js
index 5b877552d..de1aed98f 100644
--- a/app/views/RoomInfoEditView/SwitchContainer.js
+++ b/app/views/RoomInfoEditView/SwitchContainer.js
@@ -5,45 +5,50 @@ import PropTypes from 'prop-types';
import styles from './styles';
import { SWITCH_TRACK_COLOR, themes } from '../../constants/colors';
-export default class SwitchContainer extends React.PureComponent {
- static propTypes = {
- value: PropTypes.bool,
- disabled: PropTypes.bool,
- leftLabelPrimary: PropTypes.string,
- leftLabelSecondary: PropTypes.string,
- rightLabelPrimary: PropTypes.string,
- rightLabelSecondary: PropTypes.string,
- onValueChange: PropTypes.func,
- theme: PropTypes.string,
- testID: PropTypes.string
- }
+const SwitchContainer = React.memo(({
+ children, value, disabled, onValueChange, leftLabelPrimary, leftLabelSecondary, rightLabelPrimary, rightLabelSecondary, theme, testID, labelContainerStyle, leftLabelStyle
+}) => (
+ <>
+
+ {leftLabelPrimary && (
+
+ {leftLabelPrimary}
+ {leftLabelSecondary}
+
+ )}
+
+ {rightLabelPrimary && (
+
+ {rightLabelPrimary}
+ {rightLabelSecondary}
+
+ )}
+
+ {children}
+
+ >
+));
- render() {
- const {
- value, disabled, onValueChange, leftLabelPrimary, leftLabelSecondary, rightLabelPrimary, rightLabelSecondary, theme, testID
- } = this.props;
- return (
- [
-
-
- {leftLabelPrimary}
- {leftLabelSecondary}
-
-
-
- {rightLabelPrimary}
- {rightLabelSecondary}
-
- ,
-
- ]
- );
- }
-}
+SwitchContainer.propTypes = {
+ value: PropTypes.bool,
+ disabled: PropTypes.bool,
+ leftLabelPrimary: PropTypes.string,
+ leftLabelSecondary: PropTypes.string,
+ rightLabelPrimary: PropTypes.string,
+ rightLabelSecondary: PropTypes.string,
+ onValueChange: PropTypes.func,
+ theme: PropTypes.string,
+ testID: PropTypes.string,
+ labelContainerStyle: PropTypes.object,
+ leftLabelStyle: PropTypes.object,
+ children: PropTypes.any
+};
+
+export default SwitchContainer;
diff --git a/app/views/RoomInfoEditView/index.js b/app/views/RoomInfoEditView/index.js
index 58e8f1248..fe217ec1a 100644
--- a/app/views/RoomInfoEditView/index.js
+++ b/app/views/RoomInfoEditView/index.js
@@ -6,6 +6,9 @@ import {
import { connect } from 'react-redux';
import { SafeAreaView } from 'react-navigation';
import equal from 'deep-equal';
+import { BLOCK_CONTEXT } from '@rocket.chat/ui-kit';
+import isEqual from 'lodash/isEqual';
+import semver from 'semver';
import database from '../../lib/database';
import { deleteRoomInit as deleteRoomInitAction } from '../../actions/room';
@@ -27,6 +30,8 @@ import StatusBar from '../../containers/StatusBar';
import { themedHeader } from '../../utils/navigation';
import { themes } from '../../constants/colors';
import { withTheme } from '../../theme';
+import { MultiSelect } from '../../containers/UIKit/MultiSelect';
+import { MessageTypeValues } from '../../utils/messageTypes';
const PERMISSION_SET_READONLY = 'set-readonly';
const PERMISSION_SET_REACT_WHEN_READONLY = 'set-react-when-readonly';
@@ -52,6 +57,7 @@ class RoomInfoEditView extends React.Component {
static propTypes = {
navigation: PropTypes.object,
deleteRoomInit: PropTypes.func,
+ serverVersion: PropTypes.string,
theme: PropTypes.string
};
@@ -70,7 +76,9 @@ class RoomInfoEditView extends React.Component {
t: false,
ro: false,
reactWhenReadOnly: false,
- archived: false
+ archived: false,
+ systemMessages: [],
+ enableSysMes: false
};
this.loadRoom();
}
@@ -117,7 +125,7 @@ class RoomInfoEditView extends React.Component {
init = (room) => {
const {
- name, description, topic, announcement, t, ro, reactWhenReadOnly, joinCodeRequired
+ name, description, topic, announcement, t, ro, reactWhenReadOnly, joinCodeRequired, sysMes
} = room;
// fake password just to user knows about it
this.randomValue = random(15);
@@ -131,7 +139,9 @@ class RoomInfoEditView extends React.Component {
ro,
reactWhenReadOnly,
joinCode: joinCodeRequired ? this.randomValue : '',
- archived: room.archived
+ archived: room.archived,
+ systemMessages: sysMes,
+ enableSysMes: sysMes && sysMes.length > 0
});
}
@@ -148,7 +158,7 @@ class RoomInfoEditView extends React.Component {
formIsChanged = () => {
const {
- room, name, description, topic, announcement, t, ro, reactWhenReadOnly, joinCode
+ room, name, description, topic, announcement, t, ro, reactWhenReadOnly, joinCode, systemMessages, enableSysMes
} = this.state;
const { joinCodeRequired } = room;
return !(room.name === name
@@ -159,13 +169,15 @@ class RoomInfoEditView extends React.Component {
&& room.t === 'p' === t
&& room.ro === ro
&& room.reactWhenReadOnly === reactWhenReadOnly
+ && isEqual(room.sysMes, systemMessages)
+ && enableSysMes === (room.sysMes && room.sysMes.length > 0)
);
}
submit = async() => {
Keyboard.dismiss();
const {
- room, name, description, topic, announcement, t, ro, reactWhenReadOnly, joinCode
+ room, name, description, topic, announcement, t, ro, reactWhenReadOnly, joinCode, systemMessages
} = this.state;
this.setState({ saving: true });
@@ -210,6 +222,10 @@ class RoomInfoEditView extends React.Component {
params.reactWhenReadOnly = reactWhenReadOnly;
}
+ if (!isEqual(room.sysMes, systemMessages)) {
+ params.systemMessages = systemMessages;
+ }
+
// Join Code
if (this.randomValue !== joinCode) {
params.joinCode = joinCode;
@@ -298,12 +314,34 @@ class RoomInfoEditView extends React.Component {
return (permissions[PERMISSION_ARCHIVE] || permissions[PERMISSION_UNARCHIVE]);
};
+ renderSystemMessages = () => {
+ const { systemMessages, enableSysMes } = this.state;
+ const { theme } = this.props;
+
+ if (!enableSysMes) {
+ return null;
+ }
+
+ return (
+ ({ value: m.value, text: { text: I18n.t('Hide_type_messages', { type: I18n.t(m.text) }) } }))}
+ onChange={({ value }) => this.setState({ systemMessages: value })}
+ placeholder={{ text: I18n.t('Hide_System_Messages') }}
+ value={systemMessages}
+ context={BLOCK_CONTEXT.FORM}
+ multiselect
+ theme={theme}
+ />
+ );
+ }
+
render() {
const {
- name, nameError, description, topic, announcement, t, ro, reactWhenReadOnly, room, joinCode, saving, permissions, archived
+ name, nameError, description, topic, announcement, t, ro, reactWhenReadOnly, room, joinCode, saving, permissions, archived, enableSysMes
} = this.state;
- const { theme } = this.props;
+ const { serverVersion, theme } = this.props;
const { dangerColor } = themes[theme];
+
return (
this.setState(({ systemMessages }) => ({ enableSysMes: value, systemMessages: value ? systemMessages : [] }))}
+ labelContainerStyle={styles.hideSystemMessages}
+ leftLabelStyle={styles.systemMessagesLabel}
+ >
+ {this.renderSystemMessages()}
+
+ ) : null}
({
+ serverVersion: state.server.version
+});
+
const mapDispatchToProps = dispatch => ({
deleteRoomInit: (rid, t) => dispatch(deleteRoomInitAction(rid, t))
});
-export default connect(null, mapDispatchToProps)(withTheme(RoomInfoEditView));
+export default connect(mapStateToProps, mapDispatchToProps)(withTheme(RoomInfoEditView));
diff --git a/app/views/RoomInfoEditView/styles.js b/app/views/RoomInfoEditView/styles.js
index b63ae9987..bf857940f 100644
--- a/app/views/RoomInfoEditView/styles.js
+++ b/app/views/RoomInfoEditView/styles.js
@@ -63,5 +63,14 @@ export default StyleSheet.create({
broadcast: {
...sharedStyles.textAlignCenter,
...sharedStyles.textSemibold
+ },
+ hideSystemMessages: {
+ alignItems: 'flex-start'
+ },
+ systemMessagesLabel: {
+ textAlign: 'left'
+ },
+ switchMargin: {
+ marginBottom: 16
}
});
diff --git a/app/views/RoomView/List.js b/app/views/RoomView/List.js
index 238fb319d..5ca13644b 100644
--- a/app/views/RoomView/List.js
+++ b/app/views/RoomView/List.js
@@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
import orderBy from 'lodash/orderBy';
import { Q } from '@nozbe/watermelondb';
import moment from 'moment';
+import isEqual from 'lodash/isEqual';
import styles from './styles';
import database from '../../lib/database';
@@ -62,9 +63,15 @@ class List extends React.Component {
// eslint-disable-next-line react/sort-comp
async init() {
- const { rid, tmid, hideSystemMessages = [] } = this.props;
+ const { rid, tmid } = this.props;
const db = database.active;
+ // handle servers with version < 3.0.0
+ let { hideSystemMessages = [] } = this.props;
+ if (!Array.isArray(hideSystemMessages)) {
+ hideSystemMessages = [];
+ }
+
if (tmid) {
try {
this.thread = await db.collections
@@ -103,6 +110,12 @@ class List extends React.Component {
}
}
+ // eslint-disable-next-line react/sort-comp
+ reload = () => {
+ this.unsubscribeMessages();
+ this.init();
+ }
+
// this.state.loading works for this.onEndReached and RoomView.init
static getDerivedStateFromProps(props, state) {
if (props.loading !== state.loading) {
@@ -115,7 +128,7 @@ class List extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
const { loading, end, refreshing } = this.state;
- const { theme } = this.props;
+ const { hideSystemMessages, theme } = this.props;
if (theme !== nextProps.theme) {
return true;
}
@@ -128,9 +141,19 @@ class List extends React.Component {
if (refreshing !== nextState.refreshing) {
return true;
}
+ if (!isEqual(hideSystemMessages, nextProps.hideSystemMessages)) {
+ return true;
+ }
return false;
}
+ componentDidUpdate(prevProps) {
+ const { hideSystemMessages } = this.props;
+ if (!isEqual(hideSystemMessages, prevProps.hideSystemMessages)) {
+ this.reload();
+ }
+ }
+
componentWillUnmount() {
this.unsubscribeMessages();
if (this.interaction && this.interaction.cancel) {
diff --git a/app/views/RoomView/index.js b/app/views/RoomView/index.js
index 1da342dc2..2dd13f2d9 100644
--- a/app/views/RoomView/index.js
+++ b/app/views/RoomView/index.js
@@ -69,7 +69,7 @@ const stateAttrsUpdate = [
'reacting',
'showAnnouncementModal'
];
-const roomAttrsUpdate = ['f', 'ro', 'blocked', 'blocker', 'archived', 'muted', 'jitsiTimeout', 'announcement'];
+const roomAttrsUpdate = ['f', 'ro', 'blocked', 'blocker', 'archived', 'muted', 'jitsiTimeout', 'announcement', 'sysMes'];
class RoomView extends React.Component {
static navigationOptions = ({ navigation, screenProps }) => {
@@ -961,7 +961,7 @@ class RoomView extends React.Component {
const {
user, baseUrl, theme, navigation, Hide_System_Messages
} = this.props;
- const { rid, t } = room;
+ const { rid, t, sysMes } = room;
return (
{this.renderAnnouncementModal()}
{this.renderFooter()}