forked from Ivasoft/mattermost-mobile
Compare commits
30 Commits
migrate-to
...
mm-44652-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a4b61b9c7 | ||
|
|
2da4f45a31 | ||
|
|
da3f396f5b | ||
|
|
5d94ccf06b | ||
|
|
1b5b1b4591 | ||
|
|
b2cbe8b570 | ||
|
|
3176c2fed5 | ||
|
|
b27c72e965 | ||
|
|
7b1a4d6275 | ||
|
|
701c010bdf | ||
|
|
e5db26ed35 | ||
|
|
9d34726bc3 | ||
|
|
8581765196 | ||
|
|
9f3e35a9bc | ||
|
|
89387bf36b | ||
|
|
f1261535b7 | ||
|
|
dde547a919 | ||
|
|
b46ba9aa5d | ||
|
|
d9b4d18d69 | ||
|
|
cae2b818f3 | ||
|
|
3a56209562 | ||
|
|
eef1e90bf2 | ||
|
|
aa814243b5 | ||
|
|
fc16af723a | ||
|
|
273f098bee | ||
|
|
385105b621 | ||
|
|
bbcbca1675 | ||
|
|
898942b60d | ||
|
|
461bbbbfad | ||
|
|
ae0689a05b |
@@ -1154,7 +1154,7 @@ export async function searchAllChannels(serverUrl: string, term: string, archive
|
||||
}
|
||||
}
|
||||
|
||||
export const updateChannelNotifyProps = async (serverUrl: string, channelId: string, props: Partial<ChannelNotifyProps>) => {
|
||||
export const updateChannelNotifyProps = async (serverUrl: string, channelId: string, props: Partial<ChannelNotifyProps>, updateLocally = false) => {
|
||||
let client: Client;
|
||||
try {
|
||||
client = NetworkManager.getClient(serverUrl);
|
||||
@@ -1172,7 +1172,20 @@ export const updateChannelNotifyProps = async (serverUrl: string, channelId: str
|
||||
const notifyProps = {...props, channel_id: channelId, user_id: userId} as ChannelNotifyProps & {channel_id: string; user_id: string};
|
||||
|
||||
await client.updateChannelNotifyProps(notifyProps);
|
||||
if (updateLocally) {
|
||||
const channelSettings = await queryMyChannelSettingsByIds(database, [channelId]).fetch();
|
||||
const myChannelSetting = channelSettings?.[0];
|
||||
|
||||
if (myChannelSetting) {
|
||||
const updatedProps: Partial<ChannelNotifyProps> = {...myChannelSetting.notifyProps, ...notifyProps};
|
||||
|
||||
await database.write(async () => {
|
||||
await myChannelSetting.update((c) => {
|
||||
c.notifyProps = updatedProps;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
return {
|
||||
notifyProps,
|
||||
};
|
||||
@@ -1191,6 +1204,10 @@ export const toggleMuteChannel = async (serverUrl: string, channelId: string, sh
|
||||
try {
|
||||
const channelSettings = await queryMyChannelSettingsByIds(database, [channelId]).fetch();
|
||||
const myChannelSetting = channelSettings?.[0];
|
||||
if (!myChannelSetting) {
|
||||
return {error: 'Channel setting not found'};
|
||||
}
|
||||
|
||||
const mark_unread = myChannelSetting.notifyProps?.mark_unread === 'mention' ? 'all' : 'mention';
|
||||
|
||||
const notifyProps: Partial<ChannelNotifyProps> = {...myChannelSetting.notifyProps, mark_unread};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React from 'react';
|
||||
import {StyleProp, TextStyle, View, ViewStyle} from 'react-native';
|
||||
import {StyleProp, TextStyle, View, ViewProps, ViewStyle} from 'react-native';
|
||||
|
||||
import FormattedText from '@components/formatted_text';
|
||||
import {useTheme} from '@context/theme';
|
||||
@@ -36,7 +36,7 @@ export type SectionText = {
|
||||
values?: MessageDescriptor;
|
||||
}
|
||||
|
||||
export type BlockProps = {
|
||||
export type BlockProps = ViewProps & {
|
||||
children: React.ReactNode;
|
||||
disableFooter?: boolean;
|
||||
disableHeader?: boolean;
|
||||
@@ -56,12 +56,16 @@ const Block = ({
|
||||
headerStyles,
|
||||
headerText,
|
||||
footerStyles,
|
||||
...props
|
||||
}: BlockProps) => {
|
||||
const theme = useTheme();
|
||||
const styles = getStyleSheet(theme);
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View
|
||||
style={styles.container}
|
||||
{...props}
|
||||
>
|
||||
{(headerText && !disableHeader) &&
|
||||
<FormattedText
|
||||
defaultMessage={headerText.defaultMessage}
|
||||
|
||||
@@ -10,7 +10,7 @@ import {switchMap, distinctUntilChanged} from 'rxjs/operators';
|
||||
import {observeChannelsWithCalls} from '@calls/state';
|
||||
import {General} from '@constants';
|
||||
import {withServerUrl} from '@context/server';
|
||||
import {observeChannelSettings, observeMyChannel, queryChannelMembers} from '@queries/servers/channel';
|
||||
import {observeIsMutedSetting, observeMyChannel, queryChannelMembers} from '@queries/servers/channel';
|
||||
import {queryDraft} from '@queries/servers/drafts';
|
||||
import {observeCurrentChannelId, observeCurrentUserId} from '@queries/servers/system';
|
||||
import {observeTeam} from '@queries/servers/team';
|
||||
@@ -19,7 +19,6 @@ import ChannelItem from './channel_item';
|
||||
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
import type ChannelModel from '@typings/database/models/servers/channel';
|
||||
import type MyChannelModel from '@typings/database/models/servers/my_channel';
|
||||
|
||||
type EnhanceProps = WithDatabaseArgs & {
|
||||
channel: ChannelModel;
|
||||
@@ -27,8 +26,6 @@ type EnhanceProps = WithDatabaseArgs & {
|
||||
serverUrl?: string;
|
||||
}
|
||||
|
||||
const observeIsMutedSetting = (mc: MyChannelModel) => observeChannelSettings(mc.database, mc.id).pipe(switchMap((s) => of$(s?.notifyProps?.mark_unread === General.MENTION)));
|
||||
|
||||
const enhance = withObservables(['channel', 'showTeamName'], ({
|
||||
channel,
|
||||
database,
|
||||
@@ -53,7 +50,7 @@ const enhance = withObservables(['channel', 'showTeamName'], ({
|
||||
if (!mc) {
|
||||
return of$(false);
|
||||
}
|
||||
return observeIsMutedSetting(mc);
|
||||
return observeIsMutedSetting(database, mc.id);
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ export const CHANNEL = 'Channel';
|
||||
export const CHANNEL_ADD_PEOPLE = 'ChannelAddPeople';
|
||||
export const CHANNEL_INFO = 'ChannelInfo';
|
||||
export const CHANNEL_MENTION = 'ChannelMention';
|
||||
export const CHANNEL_NOTIFICATION_PREFERENCE = 'ChannelNotificationPreference';
|
||||
export const CODE = 'Code';
|
||||
export const CREATE_DIRECT_MESSAGE = 'CreateDirectMessage';
|
||||
export const CREATE_OR_EDIT_CHANNEL = 'CreateOrEditChannel';
|
||||
@@ -79,6 +80,7 @@ export default {
|
||||
CHANNEL_ADD_PEOPLE,
|
||||
CHANNEL_INFO,
|
||||
CHANNEL_MENTION,
|
||||
CHANNEL_NOTIFICATION_PREFERENCE,
|
||||
CODE,
|
||||
CREATE_DIRECT_MESSAGE,
|
||||
CREATE_OR_EDIT_CHANNEL,
|
||||
|
||||
@@ -667,6 +667,10 @@ export const queryChannelsForAutocomplete = (database: Database, matchTerm: stri
|
||||
return database.get<ChannelModel>(CHANNEL).query(...clauses);
|
||||
};
|
||||
|
||||
export const observeIsMutedSetting = (database: Database, channelId: string) => observeChannelSettings(database, channelId).
|
||||
pipe(
|
||||
switchMap((s) => of$(s?.notifyProps?.mark_unread === General.MENTION)),
|
||||
);
|
||||
export const queryChannelMembers = (database: Database, channelId: string) => {
|
||||
return database.get<ChannelMembershipModel>(CHANNEL_MEMBERSHIP).query(
|
||||
Q.where('channel_id', channelId),
|
||||
|
||||
@@ -9,6 +9,7 @@ import {isTypeDMorGM} from '@utils/channel';
|
||||
|
||||
import EditChannel from './edit_channel';
|
||||
import IgnoreMentions from './ignore_mentions';
|
||||
import NotificationPreference from './notification_preference';
|
||||
import PinnedMessages from './pinned_messages';
|
||||
|
||||
// import Members from './members';
|
||||
@@ -27,7 +28,7 @@ const Options = ({channelId, type, callsEnabled}: Props) => {
|
||||
{type !== General.DM_CHANNEL &&
|
||||
<IgnoreMentions channelId={channelId}/>
|
||||
}
|
||||
{/*<NotificationPreference channelId={channelId}/>*/}
|
||||
<NotificationPreference channelId={channelId}/>
|
||||
<PinnedMessages channelId={channelId}/>
|
||||
{/* Add back in after MM-47653 is resolved. https://mattermost.atlassian.net/browse/MM-47653
|
||||
{type !== General.DM_CHANNEL &&
|
||||
|
||||
@@ -6,7 +6,7 @@ import withObservables from '@nozbe/with-observables';
|
||||
import {of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import {observeChannelSettings} from '@queries/servers/channel';
|
||||
import {observeChannel, observeChannelSettings} from '@queries/servers/channel';
|
||||
|
||||
import NotificationPreference from './notification_preference';
|
||||
|
||||
@@ -17,12 +17,15 @@ type Props = WithDatabaseArgs & {
|
||||
}
|
||||
|
||||
const enhanced = withObservables(['channelId'], ({channelId, database}: Props) => {
|
||||
const channel = observeChannel(database, channelId);
|
||||
const displayName = channel.pipe(switchMap((c) => of$(c?.displayName)));
|
||||
const settings = observeChannelSettings(database, channelId);
|
||||
const notifyLevel = settings.pipe(
|
||||
switchMap((s) => of$(s?.notifyProps.push)),
|
||||
);
|
||||
|
||||
return {
|
||||
displayName,
|
||||
notifyLevel,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -7,21 +7,40 @@ import {Platform} from 'react-native';
|
||||
|
||||
import OptionItem from '@components/option_item';
|
||||
import {NotificationLevel, Screens} from '@constants';
|
||||
import {useTheme} from '@context/theme';
|
||||
import {t} from '@i18n';
|
||||
import {goToScreen} from '@screens/navigation';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
import {changeOpacity} from '@utils/theme';
|
||||
|
||||
type Props = {
|
||||
channelId: string;
|
||||
displayName: string;
|
||||
notifyLevel: NotificationLevel;
|
||||
}
|
||||
|
||||
const NotificationPreference = ({channelId, notifyLevel}: Props) => {
|
||||
const NotificationPreference = ({channelId, displayName, notifyLevel}: Props) => {
|
||||
const {formatMessage} = useIntl();
|
||||
const theme = useTheme();
|
||||
|
||||
const title = formatMessage({id: 'channel_info.mobile_notifications', defaultMessage: 'Mobile Notifications'});
|
||||
|
||||
const goToMentions = preventDoubleTap(() => {
|
||||
goToScreen(Screens.CHANNEL_MENTION, title, {channelId});
|
||||
const goToChannelNotificationPreference = preventDoubleTap(() => {
|
||||
const options = {
|
||||
topBar: {
|
||||
title: {
|
||||
text: title,
|
||||
},
|
||||
subtitle: {
|
||||
color: changeOpacity(theme.sidebarHeaderTextColor, 0.72),
|
||||
text: displayName,
|
||||
},
|
||||
backButton: {
|
||||
popStackOnPress: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
goToScreen(Screens.CHANNEL_NOTIFICATION_PREFERENCE, title, {channelId}, options);
|
||||
});
|
||||
|
||||
const notificationLevelToText = () => {
|
||||
@@ -54,7 +73,7 @@ const NotificationPreference = ({channelId, notifyLevel}: Props) => {
|
||||
|
||||
return (
|
||||
<OptionItem
|
||||
action={goToMentions}
|
||||
action={goToChannelNotificationPreference}
|
||||
label={title}
|
||||
icon='cellphone'
|
||||
type={Platform.select({ios: 'arrow', default: 'default'})}
|
||||
|
||||
@@ -0,0 +1,305 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useCallback, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {LayoutChangeEvent, Text, TouchableOpacity, View} from 'react-native';
|
||||
|
||||
import {toggleMuteChannel, updateChannelNotifyProps} from '@actions/remote/channel';
|
||||
import CompassIcon from '@components/compass_icon';
|
||||
import {NotificationLevel} from '@constants';
|
||||
import {useServerUrl} from '@context/server';
|
||||
import {useTheme} from '@context/theme';
|
||||
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
|
||||
import useBackNavigation from '@hooks/navigate_back';
|
||||
import {t} from '@i18n';
|
||||
import {popTopScreen} from '@screens/navigation';
|
||||
import SettingBlock from '@screens/settings/setting_block';
|
||||
import SettingContainer from '@screens/settings/setting_container';
|
||||
import SettingOption from '@screens/settings/setting_option';
|
||||
import SettingSeparator from '@screens/settings/settings_separator';
|
||||
import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme';
|
||||
import {typography} from '@utils/typography';
|
||||
|
||||
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||
|
||||
type NotifPrefOptions = {
|
||||
defaultMessage: string;
|
||||
id: string;
|
||||
testID: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
const BLOCK_TITLE_HEIGHT = 13;
|
||||
|
||||
const NOTIFY_OPTIONS_THREAD: Record<string, NotifPrefOptions> = {
|
||||
THREAD_REPLIES: {
|
||||
defaultMessage: 'Notify me about replies to threads I’m following in this channel',
|
||||
id: t('channel_notification_preference.notification.thread_replies'),
|
||||
testID: 'channel_notification_preference.notification.thread_replies',
|
||||
value: 'thread_replies',
|
||||
},
|
||||
};
|
||||
|
||||
const NOTIFY_OPTIONS: Record<string, NotifPrefOptions> = {
|
||||
[NotificationLevel.ALL]: {
|
||||
defaultMessage: 'All new messages',
|
||||
id: t('channel_notification_preference.notification.all'),
|
||||
testID: 'channel_notification_preference.notification.all',
|
||||
value: NotificationLevel.ALL,
|
||||
},
|
||||
[NotificationLevel.MENTION]: {
|
||||
defaultMessage: 'Mentions, direct messages only',
|
||||
id: t('channel_notification_preference.notification.mention'),
|
||||
testID: 'channel_notification_preference.notification.mention',
|
||||
value: NotificationLevel.MENTION,
|
||||
},
|
||||
[NotificationLevel.NONE]: {
|
||||
defaultMessage: 'Nothing',
|
||||
id: t('channel_notification_preference.notification.none'),
|
||||
testID: 'channel_notification_preference.notification.none',
|
||||
value: NotificationLevel.NONE,
|
||||
},
|
||||
};
|
||||
|
||||
const NOTIFY_ABOUT = {id: t('channel_notification_preference.notify_about'), defaultMessage: 'Notify me about...'};
|
||||
const THREAD_REPLIES = {id: t('channel_notification_preference.thread_replies'), defaultMessage: 'Thread replies'};
|
||||
const RESET_DEFAULT = {id: t('channel_notification_preference.reset_default'), defaultMessage: 'Reset to default'};
|
||||
const UNMUTE_CONTENT = {id: t('channel_notification_preference.unmute_content'), defaultMessage: 'Unmute channel'};
|
||||
const MUTED_TITLE = {id: t('channel_notification_preference.muted_title'), defaultMessage: 'This channel is muted'};
|
||||
const MUTED_CONTENT = {id: t('channel_notification_preference.muted_content'), defaultMessage: 'You can change the notification settings, but you will not receive notifications until the channel is unmuted.'};
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
||||
return {
|
||||
mutedBanner: {
|
||||
width: '90%',
|
||||
minHeight: 200,
|
||||
backgroundColor: changeOpacity(theme.sidebarTextActiveBorder, 0.16),
|
||||
alignSelf: 'center',
|
||||
marginVertical: 20,
|
||||
paddingHorizontal: 16,
|
||||
borderRadius: 4,
|
||||
},
|
||||
mutedBannerTitle: {
|
||||
flexDirection: 'row',
|
||||
marginTop: 16,
|
||||
},
|
||||
mutedTextTitle: {
|
||||
...typography('Heading', 200),
|
||||
color: theme.centerChannelColor,
|
||||
marginLeft: 10,
|
||||
paddingTop: 5,
|
||||
},
|
||||
mutedText: {
|
||||
...typography('Body', 200),
|
||||
color: theme.centerChannelColor,
|
||||
marginTop: 12,
|
||||
marginBottom: 16,
|
||||
},
|
||||
unMuteButton: {
|
||||
flexDirection: 'row',
|
||||
backgroundColor: theme.buttonBg,
|
||||
marginBottom: 20,
|
||||
borderRadius: 4,
|
||||
paddingVertical: 12,
|
||||
width: '55%',
|
||||
paddingHorizontal: 20,
|
||||
},
|
||||
unMuteText: {
|
||||
...typography('Heading', 100),
|
||||
color: theme.buttonColor,
|
||||
marginLeft: 7,
|
||||
},
|
||||
resetIcon: {
|
||||
color: theme.linkColor,
|
||||
height: 18,
|
||||
width: 18,
|
||||
},
|
||||
resetText: {
|
||||
color: theme.linkColor,
|
||||
marginLeft: 7,
|
||||
...typography('Heading', 100),
|
||||
},
|
||||
resetContainer: {
|
||||
position: 'absolute',
|
||||
flexDirection: 'row',
|
||||
right: 20,
|
||||
zIndex: 1,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
type NotifyPrefType = typeof NotificationLevel[keyof typeof NotificationLevel];
|
||||
type ChannelNotifyPropsPushThread = ChannelNotifyProps['push_threads'];
|
||||
type ChannelNotifyPropsPush = ChannelNotifyProps['push'];
|
||||
type ChannelNotificationPreferenceProps = {
|
||||
channelId: string;
|
||||
componentId: AvailableScreens;
|
||||
isCRTEnabled: boolean;
|
||||
isChannelMuted: boolean;
|
||||
globalDefault: ChannelNotifyPropsPush;
|
||||
notifyThreadReplies: ChannelNotifyPropsPushThread;
|
||||
channelNotifyLevel: ChannelNotifyPropsPush;
|
||||
channelNotifyThreadReplies: ChannelNotifyPropsPushThread;
|
||||
};
|
||||
const ChannelNotificationPreference = ({
|
||||
channelId,
|
||||
componentId,
|
||||
isCRTEnabled,
|
||||
isChannelMuted,
|
||||
globalDefault,
|
||||
notifyThreadReplies,
|
||||
channelNotifyLevel,
|
||||
channelNotifyThreadReplies,
|
||||
}: ChannelNotificationPreferenceProps) => {
|
||||
const serverUrl = useServerUrl();
|
||||
const intl = useIntl();
|
||||
const theme = useTheme();
|
||||
const styles = getStyleSheet(theme);
|
||||
const [top, setTop] = useState(0);
|
||||
|
||||
// const globalDefault = notifyLevel === 'default' ? 'all' : notifyLevel;
|
||||
const [notifyAbout, setNotifyAbout] = useState<UserNotifyPropsPush>(channelNotifyLevel === 'default' ? 'all' : channelNotifyLevel);
|
||||
const [threadReplies, setThreadReplies] = useState<boolean>((channelNotifyThreadReplies || notifyThreadReplies) === 'all');
|
||||
|
||||
const [resetDefaultVisible, setResetDefaultVisible] = useState<boolean>(false);
|
||||
|
||||
const onSetNotifyAbout = useCallback((notifyValue: NotifyPrefType) => {
|
||||
setNotifyAbout(notifyValue);
|
||||
setResetDefaultVisible(notifyValue !== globalDefault);
|
||||
}, [globalDefault]);
|
||||
|
||||
const onSetThreadReplies = useCallback(() => {
|
||||
setThreadReplies((prev) => !prev);
|
||||
}, []);
|
||||
|
||||
const close = () => popTopScreen(componentId);
|
||||
|
||||
const saveChannelNotificationPref = useCallback(() => {
|
||||
if (resetDefaultVisible) {
|
||||
const props: Partial<ChannelNotifyProps> = {
|
||||
push: notifyAbout,
|
||||
push_threads: threadReplies ? 'all' : 'mention',
|
||||
};
|
||||
updateChannelNotifyProps(serverUrl, channelId, props);
|
||||
}
|
||||
close();
|
||||
}, [channelId, close, notifyAbout, resetDefaultVisible, serverUrl, threadReplies]);
|
||||
|
||||
const renderMutedBanner = useCallback(() => {
|
||||
const onPress = async () => {
|
||||
return toggleMuteChannel(serverUrl, channelId, false);
|
||||
};
|
||||
return (
|
||||
<View style={styles.mutedBanner}>
|
||||
<View style={styles.mutedBannerTitle}>
|
||||
<CompassIcon
|
||||
name='bell-off-outline'
|
||||
size={24}
|
||||
color={theme.linkColor}
|
||||
/>
|
||||
<Text style={styles.mutedTextTitle}>{intl.formatMessage(MUTED_TITLE)}</Text>
|
||||
</View>
|
||||
<Text style={styles.mutedText}>{intl.formatMessage(MUTED_CONTENT)}</Text>
|
||||
<TouchableOpacity
|
||||
style={styles.unMuteButton}
|
||||
onPress={onPress}
|
||||
>
|
||||
<CompassIcon
|
||||
name='bell-outline'
|
||||
size={18}
|
||||
color={theme.buttonColor}
|
||||
/>
|
||||
<Text style={styles.unMuteText}>{intl.formatMessage(UNMUTE_CONTENT)}</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
}, [intl, styles, serverUrl, channelId]);
|
||||
|
||||
const renderResetDefault = useCallback(() => {
|
||||
const onPress = () => {
|
||||
setNotifyAbout(globalDefault);
|
||||
setResetDefaultVisible(false);
|
||||
};
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={[styles.resetContainer, {top}]}
|
||||
onPress={onPress}
|
||||
>
|
||||
<CompassIcon
|
||||
name='refresh'
|
||||
style={styles.resetIcon}
|
||||
size={20}
|
||||
/>
|
||||
<Text style={styles.resetText}>
|
||||
{intl.formatMessage(RESET_DEFAULT)}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}, [top, globalDefault]);
|
||||
|
||||
const renderThreadReplies = useCallback(() => {
|
||||
const isHidden = [NotificationLevel.NONE, NotificationLevel.ALL].includes(notifyAbout);
|
||||
if (isHidden) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingBlock
|
||||
headerText={THREAD_REPLIES}
|
||||
>
|
||||
<SettingOption
|
||||
action={onSetThreadReplies}
|
||||
label={intl.formatMessage({id: NOTIFY_OPTIONS_THREAD.THREAD_REPLIES.id, defaultMessage: NOTIFY_OPTIONS_THREAD.THREAD_REPLIES.defaultMessage})}
|
||||
testID={NOTIFY_OPTIONS_THREAD.THREAD_REPLIES.testID}
|
||||
type='toggle'
|
||||
selected={threadReplies}
|
||||
/>
|
||||
<SettingSeparator/>
|
||||
</SettingBlock>
|
||||
);
|
||||
}, [notifyAbout, threadReplies, intl, onSetThreadReplies]);
|
||||
|
||||
const onLayout = useCallback((e: LayoutChangeEvent) => {
|
||||
const {y} = e.nativeEvent.layout;
|
||||
setTop(y + BLOCK_TITLE_HEIGHT);
|
||||
}, []);
|
||||
|
||||
useBackNavigation(saveChannelNotificationPref);
|
||||
|
||||
useAndroidHardwareBackHandler(componentId, saveChannelNotificationPref);
|
||||
|
||||
return (
|
||||
<SettingContainer testID='push_notification_settings'>
|
||||
{isChannelMuted && renderMutedBanner()}
|
||||
{resetDefaultVisible && renderResetDefault()}
|
||||
<SettingBlock
|
||||
headerText={NOTIFY_ABOUT}
|
||||
onLayout={onLayout}
|
||||
>
|
||||
{ Object.keys(NOTIFY_OPTIONS).map((k: string) => {
|
||||
const {id, defaultMessage, value, testID} = NOTIFY_OPTIONS[k];
|
||||
const defaultOption = k === globalDefault ? ' (default)' : '';
|
||||
const label = `${intl.formatMessage({id, defaultMessage})}${defaultOption}`;
|
||||
return (
|
||||
<View key={`notif_pref_option${k}`}>
|
||||
<SettingOption
|
||||
action={onSetNotifyAbout}
|
||||
label={label}
|
||||
selected={notifyAbout === k}
|
||||
testID={testID}
|
||||
type='select'
|
||||
value={value}
|
||||
/>
|
||||
<SettingSeparator/>
|
||||
</View>
|
||||
);
|
||||
})
|
||||
}
|
||||
</SettingBlock>
|
||||
{isCRTEnabled && renderThreadReplies()}
|
||||
</SettingContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default ChannelNotificationPreference;
|
||||
49
app/screens/channel_notification_preference/index.ts
Normal file
49
app/screens/channel_notification_preference/index.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import {of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import {observeChannelSettings, observeIsMutedSetting} from '@queries/servers/channel';
|
||||
import {observeIsCRTEnabled} from '@queries/servers/thread';
|
||||
import {observeCurrentUser} from '@queries/servers/user';
|
||||
import {getNotificationProps} from '@utils/user';
|
||||
|
||||
import ChannelNotificationPreference from './channel_notification_preference';
|
||||
|
||||
import type {WithDatabaseArgs} from '@typings/database/database';
|
||||
|
||||
type CNFProps = WithDatabaseArgs & {
|
||||
channelId: string;
|
||||
}
|
||||
const enhanced = withObservables([], ({channelId, database}: CNFProps) => {
|
||||
const settings = observeChannelSettings(database, channelId);
|
||||
const channelNotifyLevel = settings.pipe(
|
||||
switchMap((s) => of$(s?.notifyProps.push)),
|
||||
);
|
||||
const channelNotifyThreadReplies = settings.pipe(
|
||||
switchMap((s) => of$(s?.notifyProps.push_threads)),
|
||||
);
|
||||
|
||||
const notifyProps = observeCurrentUser(database).pipe(
|
||||
switchMap((u) => of$(u?.notifyProps ? getNotificationProps(u) : undefined)),
|
||||
);
|
||||
const globalDefault = notifyProps.pipe(
|
||||
switchMap((n) => of$(n?.push)),
|
||||
);
|
||||
const notifyThreadReplies = notifyProps.pipe(
|
||||
switchMap((n) => of$(n?.push_threads)),
|
||||
);
|
||||
|
||||
return {
|
||||
isCRTEnabled: observeIsCRTEnabled(database),
|
||||
isChannelMuted: observeIsMutedSetting(database, channelId),
|
||||
globalDefault,
|
||||
notifyThreadReplies,
|
||||
channelNotifyLevel,
|
||||
channelNotifyThreadReplies,
|
||||
};
|
||||
});
|
||||
export default withDatabase(enhanced(ChannelNotificationPreference));
|
||||
@@ -76,15 +76,24 @@ Navigation.setLazyComponentRegistrator((screenName) => {
|
||||
case Screens.BROWSE_CHANNELS:
|
||||
screen = withServerDatabase(require('@screens/browse_channels').default);
|
||||
break;
|
||||
case Screens.CALL:
|
||||
screen = withServerDatabase(require('@calls/screens/call_screen').default);
|
||||
break;
|
||||
case Screens.CHANNEL:
|
||||
screen = withServerDatabase(require('@screens/channel').default);
|
||||
break;
|
||||
case Screens.CHANNEL_INFO:
|
||||
screen = withServerDatabase(require('@screens/channel_info').default);
|
||||
break;
|
||||
case Screens.CHANNEL_NOTIFICATION_PREFERENCE:
|
||||
screen = withServerDatabase(require('@screens/channel_notification_preference').default);
|
||||
break;
|
||||
case Screens.CODE:
|
||||
screen = withServerDatabase(require('@screens/code').default);
|
||||
break;
|
||||
case Screens.CREATE_DIRECT_MESSAGE:
|
||||
screen = withServerDatabase(require('@screens/create_direct_message').default);
|
||||
break;
|
||||
case Screens.CREATE_OR_EDIT_CHANNEL:
|
||||
screen = withServerDatabase(require('@screens/create_or_edit_channel').default);
|
||||
break;
|
||||
@@ -94,9 +103,6 @@ Navigation.setLazyComponentRegistrator((screenName) => {
|
||||
case Screens.CUSTOM_STATUS_CLEAR_AFTER:
|
||||
screen = withServerDatabase(require('@screens/custom_status_clear_after').default);
|
||||
break;
|
||||
case Screens.CREATE_DIRECT_MESSAGE:
|
||||
screen = withServerDatabase(require('@screens/create_direct_message').default);
|
||||
break;
|
||||
case Screens.EDIT_POST:
|
||||
screen = withServerDatabase(require('@screens/edit_post').default);
|
||||
break;
|
||||
@@ -121,12 +127,12 @@ Navigation.setLazyComponentRegistrator((screenName) => {
|
||||
case Screens.GLOBAL_THREADS:
|
||||
screen = withServerDatabase(require('@screens/global_threads').default);
|
||||
break;
|
||||
case Screens.INTERACTIVE_DIALOG:
|
||||
screen = withServerDatabase(require('@screens/interactive_dialog').default);
|
||||
break;
|
||||
case Screens.INTEGRATION_SELECTOR:
|
||||
screen = withServerDatabase(require('@screens/integration_selector').default);
|
||||
break;
|
||||
case Screens.INTERACTIVE_DIALOG:
|
||||
screen = withServerDatabase(require('@screens/interactive_dialog').default);
|
||||
break;
|
||||
case Screens.INVITE:
|
||||
screen = withServerDatabase(require('@screens/invite').default);
|
||||
break;
|
||||
@@ -152,9 +158,6 @@ Navigation.setLazyComponentRegistrator((screenName) => {
|
||||
case Screens.MFA:
|
||||
screen = withIntl(require('@screens/mfa').default);
|
||||
break;
|
||||
case Screens.SELECT_TEAM:
|
||||
screen = withServerDatabase(require('@screens/select_team').default);
|
||||
break;
|
||||
case Screens.PERMALINK:
|
||||
screen = withServerDatabase(require('@screens/permalink').default);
|
||||
break;
|
||||
@@ -170,6 +173,9 @@ Navigation.setLazyComponentRegistrator((screenName) => {
|
||||
case Screens.REVIEW_APP:
|
||||
screen = withServerDatabase(require('@screens/review_app').default);
|
||||
break;
|
||||
case Screens.SELECT_TEAM:
|
||||
screen = withServerDatabase(require('@screens/select_team').default);
|
||||
break;
|
||||
case Screens.SETTINGS:
|
||||
screen = withServerDatabase(require('@screens/settings').default);
|
||||
break;
|
||||
@@ -245,9 +251,6 @@ Navigation.setLazyComponentRegistrator((screenName) => {
|
||||
case Screens.USER_PROFILE:
|
||||
screen = withServerDatabase(require('@screens/user_profile').default);
|
||||
break;
|
||||
case Screens.CALL:
|
||||
screen = withServerDatabase(require('@calls/screens/call_screen').default);
|
||||
break;
|
||||
}
|
||||
|
||||
if (screen) {
|
||||
|
||||
@@ -74,19 +74,23 @@ const NotificationPush = ({componentId, currentUser, isCRTEnabled, sendPushNotif
|
||||
sendPushNotifications={sendPushNotifications}
|
||||
setMobilePushPref={setPushSend}
|
||||
/>
|
||||
{Platform.OS === 'android' && (<SettingSeparator isGroupSeparator={true}/>)}
|
||||
{isCRTEnabled && pushSend === 'mention' && (
|
||||
<MobilePushThread
|
||||
pushThread={pushThread}
|
||||
onMobilePushThreadChanged={onMobilePushThreadChanged}
|
||||
/>
|
||||
<>
|
||||
{Platform.OS === 'android' && (<SettingSeparator isGroupSeparator={true}/>)}
|
||||
<MobilePushThread
|
||||
pushThread={pushThread}
|
||||
onMobilePushThreadChanged={onMobilePushThreadChanged}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{Platform.OS === 'android' && (<SettingSeparator isGroupSeparator={true}/>)}
|
||||
{sendPushNotifications && pushSend !== 'none' && (
|
||||
<MobilePushStatus
|
||||
pushStatus={pushStatus}
|
||||
setMobilePushStatus={setPushStatus}
|
||||
/>
|
||||
<>
|
||||
{Platform.OS === 'android' && (<SettingSeparator isGroupSeparator={true}/>)}
|
||||
<MobilePushStatus
|
||||
pushStatus={pushStatus}
|
||||
setMobilePushStatus={setPushStatus}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</SettingContainer>
|
||||
);
|
||||
|
||||
@@ -168,6 +168,16 @@
|
||||
"channel_modal.optional": "(optional)",
|
||||
"channel_modal.purpose": "Purpose",
|
||||
"channel_modal.purposeEx": "A channel to file bugs and improvements",
|
||||
"channel_notification_preference.muted_content": "You can change the notification settings, but you will not receive notifications until the channel is unmuted.",
|
||||
"channel_notification_preference.muted_title": "This channel is muted",
|
||||
"channel_notification_preference.notification.all": "All new messages",
|
||||
"channel_notification_preference.notification.mention": "Mentions, direct messages only",
|
||||
"channel_notification_preference.notification.none": "Nothing",
|
||||
"channel_notification_preference.notification.thread_replies": "Notify me about replies to threads I’m following in this channel",
|
||||
"channel_notification_preference.notify_about": "Notify me about...",
|
||||
"channel_notification_preference.reset_default": "Reset to default",
|
||||
"channel_notification_preference.thread_replies": "Thread replies",
|
||||
"channel_notification_preference.unmute_content": "Unmute channel",
|
||||
"combined_system_message.added_to_channel.many_expanded": "{users} and {lastUser} were **added to the channel** by {actor}.",
|
||||
"combined_system_message.added_to_channel.one": "{firstUser} **added to the channel** by {actor}.",
|
||||
"combined_system_message.added_to_channel.one_you": "You were **added to the channel** by {actor}.",
|
||||
@@ -340,6 +350,7 @@
|
||||
"invite.send_invite": "Send",
|
||||
"invite.sendInvitationsTo": "Send invitations to…",
|
||||
"invite.shareLink": "Share link",
|
||||
"invite.summary.back": "Go back",
|
||||
"invite.summary.done": "Done",
|
||||
"invite.summary.email_invite": "An invitation email has been sent",
|
||||
"invite.summary.error": "{invitationsCount, plural, one {Invitation} other {Invitations}} could not be sent successfully",
|
||||
|
||||
3
types/api/channels.d.ts
vendored
3
types/api/channels.d.ts
vendored
@@ -13,9 +13,10 @@ type NotificationLevel = 'default' | 'all' | 'mention' | 'none';
|
||||
type ChannelNotifyProps = {
|
||||
desktop: NotificationLevel;
|
||||
email: NotificationLevel;
|
||||
ignore_channel_mentions: 'default' | 'off' | 'on';
|
||||
mark_unread: 'all' | 'mention';
|
||||
push: NotificationLevel;
|
||||
ignore_channel_mentions: 'default' | 'off' | 'on';
|
||||
push_threads: 'all' | 'mention';
|
||||
};
|
||||
type Channel = {
|
||||
id: string;
|
||||
|
||||
Reference in New Issue
Block a user