Add GM as DM feature support (#7515)
* Add GM as DM feature support * Minor fix * Address feedback * Fix case for non set channel notify prop * Fix strings
This commit is contained in:
parent
0ec2b09fd5
commit
ba52acb26f
21 changed files with 282 additions and 47 deletions
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {getActiveServerUrl} from '@app/init/credentials';
|
||||
import {Tutorial} from '@constants';
|
||||
import {GLOBAL_IDENTIFIERS} from '@constants/database';
|
||||
import DatabaseManager from '@database/manager';
|
||||
import {getActiveServerUrl} from '@init/credentials';
|
||||
import {logError} from '@utils/log';
|
||||
|
||||
export const storeGlobal = async (id: string, value: unknown, prepareRecordsOnly = false) => {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
export const ALL = 'all';
|
||||
export const DEFAULT = 'default';
|
||||
export const MENTION = 'mention';
|
||||
export const NONE = 'none';
|
||||
export const ALL = 'all' as const;
|
||||
export const DEFAULT = 'default' as const;
|
||||
export const MENTION = 'mention' as const;
|
||||
export const NONE = 'none' as const;
|
||||
|
||||
export default {
|
||||
ALL,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
export const CATEGORIES_TO_KEEP: Record<string, string> = {
|
||||
export const CATEGORIES_TO_KEEP = {
|
||||
ADVANCED_SETTINGS: 'advanced_settings',
|
||||
CHANNEL_APPROXIMATE_VIEW_TIME: 'channel_approximate_view_time',
|
||||
CHANNEL_OPEN_TIME: 'channel_open_time',
|
||||
|
|
@ -14,15 +14,21 @@ export const CATEGORIES_TO_KEEP: Record<string, string> = {
|
|||
SIDEBAR_SETTINGS: 'sidebar_settings',
|
||||
TEAMS_ORDER: 'teams_order',
|
||||
THEME: 'theme',
|
||||
SYSTEM_NOTICE: 'system_notice',
|
||||
};
|
||||
|
||||
const CATEGORIES: Record<string, string> = {
|
||||
const CATEGORIES = {
|
||||
...CATEGORIES_TO_KEEP,
|
||||
FAVORITE_CHANNEL: 'favorite_channel',
|
||||
};
|
||||
|
||||
const NOTICES = {
|
||||
GM_AS_DM: 'GMasDM',
|
||||
};
|
||||
|
||||
const Preferences = {
|
||||
CATEGORIES,
|
||||
NOTICES,
|
||||
COLLAPSED_REPLY_THREADS: 'collapsed_reply_threads',
|
||||
COLLAPSED_REPLY_THREADS_OFF: 'off',
|
||||
COLLAPSED_REPLY_THREADS_ON: 'on',
|
||||
|
|
|
|||
4
app/constants/versions.ts
Normal file
4
app/constants/versions.ts
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
export const GM_AS_DM_VERSION = [9, 1, 0];
|
||||
18
app/queries/servers/features.ts
Normal file
18
app/queries/servers/features.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import {GM_AS_DM_VERSION} from '@constants/versions';
|
||||
import {isMinimumServerVersion} from '@utils/helpers';
|
||||
|
||||
import {observeConfigValue} from './system';
|
||||
|
||||
import type {Database} from '@nozbe/watermelondb';
|
||||
|
||||
export const observeHasGMasDMFeature = (database: Database) => {
|
||||
return observeConfigValue(database, 'Version').pipe(
|
||||
switchMap((v) => of$(isMinimumServerVersion(v, ...GM_AS_DM_VERSION))),
|
||||
);
|
||||
};
|
||||
|
|
@ -24,7 +24,9 @@ import EphemeralStore from '@store/ephemeral_store';
|
|||
|
||||
import ChannelPostList from './channel_post_list';
|
||||
import ChannelHeader from './header';
|
||||
import useGMasDMNotice from './use_gm_as_dm_notice';
|
||||
|
||||
import type PreferenceModel from '@typings/database/models/servers/preference';
|
||||
import type {AvailableScreens} from '@typings/screens/navigation';
|
||||
import type {KeyboardTrackingViewRef} from 'react-native-keyboard-tracking-view';
|
||||
|
||||
|
|
@ -36,6 +38,10 @@ type ChannelProps = {
|
|||
isCallsEnabledInChannel: boolean;
|
||||
showIncomingCalls: boolean;
|
||||
isTabletView?: boolean;
|
||||
dismissedGMasDMNotice: PreferenceModel[];
|
||||
currentUserId: string;
|
||||
channelType: ChannelType;
|
||||
hasGMasDMFeature: boolean;
|
||||
};
|
||||
|
||||
const edges: Edge[] = ['left', 'right'];
|
||||
|
|
@ -55,7 +61,12 @@ const Channel = ({
|
|||
isCallsEnabledInChannel,
|
||||
showIncomingCalls,
|
||||
isTabletView,
|
||||
dismissedGMasDMNotice,
|
||||
channelType,
|
||||
currentUserId,
|
||||
hasGMasDMFeature,
|
||||
}: ChannelProps) => {
|
||||
useGMasDMNotice(currentUserId, channelType, dismissedGMasDMNotice, hasGMasDMFeature);
|
||||
const isTablet = useIsTablet();
|
||||
const insets = useSafeAreaInsets();
|
||||
const [shouldRenderPosts, setShouldRenderPosts] = useState(false);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ type Props = {
|
|||
isBot: boolean;
|
||||
members?: ChannelMembershipModel[];
|
||||
theme: Theme;
|
||||
hasGMasDMFeature: boolean;
|
||||
}
|
||||
|
||||
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
||||
|
|
@ -52,6 +53,9 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
|||
textAlign: 'center',
|
||||
...typography('Body', 200, 'Regular'),
|
||||
},
|
||||
boldText: {
|
||||
...typography('Body', 200, 'SemiBold'),
|
||||
},
|
||||
profilesContainer: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
|
|
@ -67,7 +71,14 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
|
|||
},
|
||||
}));
|
||||
|
||||
const DirectChannel = ({channel, currentUserId, isBot, members, theme}: Props) => {
|
||||
const DirectChannel = ({
|
||||
channel,
|
||||
currentUserId,
|
||||
isBot,
|
||||
members,
|
||||
theme,
|
||||
hasGMasDMFeature,
|
||||
}: Props) => {
|
||||
const serverUrl = useServerUrl();
|
||||
const styles = getStyleSheet(theme);
|
||||
|
||||
|
|
@ -89,11 +100,23 @@ const DirectChannel = ({channel, currentUserId, isBot, members, theme}: Props) =
|
|||
/>
|
||||
);
|
||||
}
|
||||
if (!hasGMasDMFeature) {
|
||||
return (
|
||||
<FormattedText
|
||||
defaultMessage={'This is the start of your conversation with this group. Messages and files shared here are not shown to anyone else outside of the group.'}
|
||||
id='intro.group_message.after_gm_as_dm'
|
||||
style={styles.message}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<FormattedText
|
||||
defaultMessage={'This is the start of your conversation with this group. Messages and files shared here are not shown to anyone else outside of the group.'}
|
||||
defaultMessage={'This is the start of your conversation with this group. You\'ll be notified for <b>all activity</b> in this group message.'}
|
||||
id='intro.group_message'
|
||||
style={styles.message}
|
||||
values={{
|
||||
b: (chunk: string) => <Text style={styles.boldText}>{chunk}</Text>,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}, [channel.displayName, theme]);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import {switchMap} from 'rxjs/operators';
|
|||
|
||||
import {General} from '@constants';
|
||||
import {observeChannelMembers} from '@queries/servers/channel';
|
||||
import {observeHasGMasDMFeature} from '@queries/servers/features';
|
||||
import {observeCurrentUserId} from '@queries/servers/system';
|
||||
import {observeUser} from '@queries/servers/user';
|
||||
import {getUserIdFromChannelName} from '@utils/user';
|
||||
|
|
@ -23,6 +24,7 @@ const observeIsBot = (user: UserModel | undefined) => of$(Boolean(user?.isBot));
|
|||
const enhanced = withObservables([], ({channel, database}: {channel: ChannelModel} & WithDatabaseArgs) => {
|
||||
const currentUserId = observeCurrentUserId(database);
|
||||
const members = observeChannelMembers(database, channel.id);
|
||||
const hasGMasDMFeature = observeHasGMasDMFeature(database);
|
||||
let isBot = of$(false);
|
||||
|
||||
if (channel.type === General.DM_CHANNEL) {
|
||||
|
|
@ -40,6 +42,7 @@ const enhanced = withObservables([], ({channel, database}: {channel: ChannelMode
|
|||
currentUserId,
|
||||
isBot,
|
||||
members,
|
||||
hasGMasDMFeature,
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -12,8 +12,12 @@ import {
|
|||
observeCurrentCall,
|
||||
observeIncomingCalls,
|
||||
} from '@calls/state';
|
||||
import {Preferences} from '@constants';
|
||||
import {withServerUrl} from '@context/server';
|
||||
import {observeCurrentChannelId} from '@queries/servers/system';
|
||||
import {observeCurrentChannel} from '@queries/servers/channel';
|
||||
import {observeHasGMasDMFeature} from '@queries/servers/features';
|
||||
import {queryPreferencesByCategoryAndName} from '@queries/servers/preference';
|
||||
import {observeCurrentChannelId, observeCurrentUserId} from '@queries/servers/system';
|
||||
|
||||
import Channel from './channel';
|
||||
|
||||
|
|
@ -56,12 +60,21 @@ const enhanced = withObservables([], ({database, serverUrl}: EnhanceProps) => {
|
|||
distinctUntilChanged(),
|
||||
);
|
||||
|
||||
const dismissedGMasDMNotice = queryPreferencesByCategoryAndName(database, Preferences.CATEGORIES.SYSTEM_NOTICE, Preferences.NOTICES.GM_AS_DM).observe();
|
||||
const channelType = observeCurrentChannel(database).pipe(switchMap((c) => of$(c?.type)));
|
||||
const currentUserId = observeCurrentUserId(database);
|
||||
const hasGMasDMFeature = observeHasGMasDMFeature(database);
|
||||
|
||||
return {
|
||||
channelId,
|
||||
showJoinCallBanner,
|
||||
isInACall,
|
||||
showIncomingCalls,
|
||||
isCallsEnabledInChannel: observeIsCallsEnabledInChannel(database, serverUrl, channelId),
|
||||
dismissedGMasDMNotice,
|
||||
channelType,
|
||||
currentUserId,
|
||||
hasGMasDMFeature,
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
|||
65
app/screens/channel/use_gm_as_dm_notice.tsx
Normal file
65
app/screens/channel/use_gm_as_dm_notice.tsx
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {useEffect} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {Alert} from 'react-native';
|
||||
|
||||
import {savePreference} from '@actions/remote/preference';
|
||||
import {Preferences} from '@constants';
|
||||
import {useServerUrl} from '@context/server';
|
||||
import {getPreferenceAsBool} from '@helpers/api/preference';
|
||||
import EphemeralStore from '@store/ephemeral_store';
|
||||
|
||||
import type PreferenceModel from '@typings/database/models/servers/preference';
|
||||
|
||||
const useGMasDMNotice = (userId: string, channelType: ChannelType, dismissedGMasDMNotice: PreferenceModel[], hasGMasDMFeature: boolean) => {
|
||||
const intl = useIntl();
|
||||
const serverUrl = useServerUrl();
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasGMasDMFeature) {
|
||||
return;
|
||||
}
|
||||
|
||||
const preferenceValue = getPreferenceAsBool(dismissedGMasDMNotice, Preferences.CATEGORIES.SYSTEM_NOTICE, Preferences.NOTICES.GM_AS_DM);
|
||||
if (preferenceValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (channelType !== 'G') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (EphemeralStore.noticeShown.has(Preferences.NOTICES.GM_AS_DM)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const onRemindMeLaterPress = () => {
|
||||
EphemeralStore.noticeShown.add(Preferences.NOTICES.GM_AS_DM);
|
||||
};
|
||||
|
||||
const onHideAndForget = () => {
|
||||
EphemeralStore.noticeShown.add(Preferences.NOTICES.GM_AS_DM);
|
||||
savePreference(serverUrl, [{category: Preferences.CATEGORIES.SYSTEM_NOTICE, name: Preferences.NOTICES.GM_AS_DM, value: 'true', user_id: userId}]);
|
||||
};
|
||||
|
||||
// Show the GM as DM notice if needed
|
||||
Alert.alert(
|
||||
intl.formatMessage({id: 'system_notice.title.gm_as_dm', defaultMessage: 'Updates to Group Messages'}),
|
||||
intl.formatMessage({id: 'system_noticy.body.gm_as_dm', defaultMessage: 'You will now be notified for all activity in your group messages along with a notification badge for every new message.\n\nYou can configure this in notification preferences for each group message.'}),
|
||||
[
|
||||
{
|
||||
text: intl.formatMessage({id: 'system_notice.remind_me', defaultMessage: 'Remind Me Later'}),
|
||||
onPress: onRemindMeLaterPress,
|
||||
},
|
||||
{
|
||||
text: intl.formatMessage({id: 'system_notice.dont_show', defaultMessage: 'Don\'t Show Again'}),
|
||||
onPress: onHideAndForget,
|
||||
},
|
||||
],
|
||||
);
|
||||
}, []);
|
||||
};
|
||||
|
||||
export default useGMasDMNotice;
|
||||
|
|
@ -6,7 +6,9 @@ import withObservables from '@nozbe/with-observables';
|
|||
import {of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
import {NotificationLevel} from '@constants';
|
||||
import {observeChannel, observeChannelSettings} from '@queries/servers/channel';
|
||||
import {observeHasGMasDMFeature} from '@queries/servers/features';
|
||||
import {observeCurrentUser} from '@queries/servers/user';
|
||||
import {getNotificationProps} from '@utils/user';
|
||||
|
||||
|
|
@ -19,17 +21,22 @@ type Props = WithDatabaseArgs & {
|
|||
}
|
||||
|
||||
const enhanced = withObservables(['channelId'], ({channelId, database}: Props) => {
|
||||
const displayName = observeChannel(database, channelId).pipe(switchMap((c) => of$(c?.displayName)));
|
||||
const channel = observeChannel(database, channelId);
|
||||
const channelType = channel.pipe(switchMap((c) => of$(c?.type)));
|
||||
const displayName = channel.pipe(switchMap((c) => of$(c?.displayName)));
|
||||
const settings = observeChannelSettings(database, channelId);
|
||||
const userNotifyLevel = observeCurrentUser(database).pipe(switchMap((u) => of$(getNotificationProps(u).push)));
|
||||
const notifyLevel = settings.pipe(
|
||||
switchMap((s) => of$(s?.notifyProps.push)),
|
||||
switchMap((s) => of$(s?.notifyProps.push || NotificationLevel.DEFAULT)),
|
||||
);
|
||||
const hasGMasDMFeature = observeHasGMasDMFeature(database);
|
||||
|
||||
return {
|
||||
displayName,
|
||||
notifyLevel,
|
||||
userNotifyLevel,
|
||||
channelType,
|
||||
hasGMasDMFeature,
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {NotificationLevel, Screens} from '@constants';
|
|||
import {useTheme} from '@context/theme';
|
||||
import {t} from '@i18n';
|
||||
import {goToScreen} from '@screens/navigation';
|
||||
import {isTypeDMorGM} from '@utils/channel';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
import {changeOpacity} from '@utils/theme';
|
||||
|
||||
|
|
@ -20,6 +21,8 @@ type Props = {
|
|||
displayName: string;
|
||||
notifyLevel: NotificationLevel;
|
||||
userNotifyLevel: NotificationLevel;
|
||||
channelType: ChannelType;
|
||||
hasGMasDMFeature: boolean;
|
||||
}
|
||||
|
||||
const notificationLevel = (notifyLevel: NotificationLevel) => {
|
||||
|
|
@ -50,7 +53,14 @@ const notificationLevel = (notifyLevel: NotificationLevel) => {
|
|||
return {id, defaultMessage};
|
||||
};
|
||||
|
||||
const NotificationPreference = ({channelId, displayName, notifyLevel, userNotifyLevel}: Props) => {
|
||||
const NotificationPreference = ({
|
||||
channelId,
|
||||
displayName,
|
||||
notifyLevel,
|
||||
userNotifyLevel,
|
||||
channelType,
|
||||
hasGMasDMFeature,
|
||||
}: Props) => {
|
||||
const {formatMessage} = useIntl();
|
||||
const theme = useTheme();
|
||||
const title = formatMessage({id: 'channel_info.mobile_notifications', defaultMessage: 'Mobile Notifications'});
|
||||
|
|
@ -74,13 +84,19 @@ const NotificationPreference = ({channelId, displayName, notifyLevel, userNotify
|
|||
});
|
||||
|
||||
const notificationLevelToText = () => {
|
||||
if (notifyLevel === NotificationLevel.DEFAULT) {
|
||||
const userLevel = notificationLevel(userNotifyLevel);
|
||||
return formatMessage(userLevel);
|
||||
let notifyLevelToUse = notifyLevel;
|
||||
if (notifyLevelToUse === NotificationLevel.DEFAULT) {
|
||||
notifyLevelToUse = userNotifyLevel;
|
||||
}
|
||||
|
||||
const channelLevel = notificationLevel(notifyLevel);
|
||||
return formatMessage(channelLevel);
|
||||
if (hasGMasDMFeature) {
|
||||
if (notifyLevel === NotificationLevel.DEFAULT && notifyLevelToUse === NotificationLevel.MENTION && isTypeDMorGM(channelType)) {
|
||||
notifyLevelToUse = NotificationLevel.ALL;
|
||||
}
|
||||
}
|
||||
|
||||
const messageDescriptor = notificationLevel(notifyLevelToUse);
|
||||
return formatMessage(messageDescriptor);
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -7,10 +7,12 @@ import {useSharedValue} from 'react-native-reanimated';
|
|||
|
||||
import {updateChannelNotifyProps} from '@actions/remote/channel';
|
||||
import SettingsContainer from '@components/settings/container';
|
||||
import {NotificationLevel} from '@constants';
|
||||
import {useServerUrl} from '@context/server';
|
||||
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
|
||||
import useDidUpdate from '@hooks/did_update';
|
||||
import useBackNavigation from '@hooks/navigate_back';
|
||||
import {isTypeDMorGM} from '@utils/channel';
|
||||
|
||||
import {popTopScreen} from '../navigation';
|
||||
|
||||
|
|
@ -28,16 +30,29 @@ type Props = {
|
|||
defaultThreadReplies: 'all' | 'mention';
|
||||
isCRTEnabled: boolean;
|
||||
isMuted: boolean;
|
||||
notifyLevel?: NotificationLevel;
|
||||
notifyLevel: NotificationLevel;
|
||||
notifyThreadReplies?: 'all' | 'mention';
|
||||
channelType: ChannelType;
|
||||
hasGMasDMFeature: boolean;
|
||||
}
|
||||
|
||||
const ChannelNotificationPreferences = ({channelId, componentId, defaultLevel, defaultThreadReplies, isCRTEnabled, isMuted, notifyLevel, notifyThreadReplies}: Props) => {
|
||||
const ChannelNotificationPreferences = ({
|
||||
channelId,
|
||||
componentId,
|
||||
defaultLevel,
|
||||
defaultThreadReplies,
|
||||
isCRTEnabled,
|
||||
isMuted,
|
||||
notifyLevel,
|
||||
notifyThreadReplies,
|
||||
channelType,
|
||||
hasGMasDMFeature,
|
||||
}: Props) => {
|
||||
const serverUrl = useServerUrl();
|
||||
const defaultNotificationReplies = defaultThreadReplies === 'all';
|
||||
const diffNotificationLevel = notifyLevel !== 'default' && notifyLevel !== defaultLevel;
|
||||
const diffNotificationLevel = notifyLevel !== NotificationLevel.DEFAULT && notifyLevel !== defaultLevel;
|
||||
const notifyTitleTop = useSharedValue((isMuted ? MUTED_BANNER_HEIGHT : 0) + BLOCK_TITLE_HEIGHT);
|
||||
const [notifyAbout, setNotifyAbout] = useState<NotificationLevel>((notifyLevel === undefined || notifyLevel === 'default') ? defaultLevel : notifyLevel);
|
||||
const [notifyAbout, setNotifyAbout] = useState<NotificationLevel>(notifyLevel === NotificationLevel.DEFAULT ? defaultLevel : notifyLevel);
|
||||
const [threadReplies, setThreadReplies] = useState<boolean>((notifyThreadReplies || defaultThreadReplies) === 'all');
|
||||
const [resetDefaultVisible, setResetDefaultVisible] = useState(diffNotificationLevel || defaultNotificationReplies !== threadReplies);
|
||||
|
||||
|
|
@ -64,8 +79,13 @@ const ChannelNotificationPreferences = ({channelId, componentId, defaultLevel, d
|
|||
const save = useCallback(() => {
|
||||
const pushThreads = threadReplies ? 'all' : 'mention';
|
||||
|
||||
if (notifyLevel !== notifyAbout || (isCRTEnabled && pushThreads !== notifyThreadReplies)) {
|
||||
const props: Partial<ChannelNotifyProps> = {push: notifyAbout};
|
||||
let notifyAboutToUse = notifyAbout;
|
||||
if (notifyAbout === defaultLevel) {
|
||||
notifyAboutToUse = NotificationLevel.DEFAULT;
|
||||
}
|
||||
|
||||
if (notifyLevel !== notifyAboutToUse || (isCRTEnabled && pushThreads !== notifyThreadReplies)) {
|
||||
const props: Partial<ChannelNotifyProps> = {push: notifyAboutToUse};
|
||||
if (isCRTEnabled) {
|
||||
props.push_threads = pushThreads;
|
||||
}
|
||||
|
|
@ -73,11 +93,15 @@ const ChannelNotificationPreferences = ({channelId, componentId, defaultLevel, d
|
|||
updateChannelNotifyProps(serverUrl, channelId, props);
|
||||
}
|
||||
popTopScreen(componentId);
|
||||
}, [channelId, componentId, isCRTEnabled, notifyAbout, notifyLevel, notifyThreadReplies, serverUrl, threadReplies]);
|
||||
}, [defaultLevel, channelId, componentId, isCRTEnabled, notifyAbout, notifyLevel, notifyThreadReplies, serverUrl, threadReplies]);
|
||||
|
||||
useBackNavigation(save);
|
||||
useAndroidHardwareBackHandler(componentId, save);
|
||||
|
||||
const showThreadReplies = isCRTEnabled && (
|
||||
!hasGMasDMFeature ||
|
||||
!isTypeDMorGM(channelType)
|
||||
);
|
||||
return (
|
||||
<SettingsContainer testID='push_notification_settings'>
|
||||
{isMuted && <MutedBanner channelId={channelId}/>}
|
||||
|
|
@ -94,7 +118,7 @@ const ChannelNotificationPreferences = ({channelId, componentId, defaultLevel, d
|
|||
notifyTitleTop={notifyTitleTop}
|
||||
onPress={onNotificationLevel}
|
||||
/>
|
||||
{isCRTEnabled &&
|
||||
{showThreadReplies &&
|
||||
<ThreadReplies
|
||||
isSelected={threadReplies}
|
||||
onPress={onSetThreadReplies}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,14 @@
|
|||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import {of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
import {switchMap, combineLatestWith} from 'rxjs/operators';
|
||||
|
||||
import {observeChannelSettings, observeIsMutedSetting} from '@queries/servers/channel';
|
||||
import {NotificationLevel} from '@constants';
|
||||
import {observeChannel, observeChannelSettings, observeIsMutedSetting} from '@queries/servers/channel';
|
||||
import {observeHasGMasDMFeature} from '@queries/servers/features';
|
||||
import {observeIsCRTEnabled} from '@queries/servers/thread';
|
||||
import {observeCurrentUser} from '@queries/servers/user';
|
||||
import {isTypeDMorGM} from '@utils/channel';
|
||||
import {getNotificationProps} from '@utils/user';
|
||||
|
||||
import ChannelNotificationPreferences from './channel_notification_preferences';
|
||||
|
|
@ -24,9 +27,11 @@ const enhanced = withObservables([], ({channelId, database}: EnhancedProps) => {
|
|||
const isCRTEnabled = observeIsCRTEnabled(database);
|
||||
const isMuted = observeIsMutedSetting(database, channelId);
|
||||
const notifyProps = observeCurrentUser(database).pipe(switchMap((u) => of$(getNotificationProps(u))));
|
||||
const channelType = observeChannel(database, channelId).pipe(switchMap((c) => of$(c?.type)));
|
||||
const hasGMasDMFeature = observeHasGMasDMFeature(database);
|
||||
|
||||
const notifyLevel = settings.pipe(
|
||||
switchMap((s) => of$(s?.notifyProps.push)),
|
||||
switchMap((s) => of$(s?.notifyProps.push || NotificationLevel.DEFAULT)),
|
||||
);
|
||||
|
||||
const notifyThreadReplies = settings.pipe(
|
||||
|
|
@ -35,7 +40,21 @@ const enhanced = withObservables([], ({channelId, database}: EnhancedProps) => {
|
|||
|
||||
const defaultLevel = notifyProps.pipe(
|
||||
switchMap((n) => of$(n?.push)),
|
||||
combineLatestWith(hasGMasDMFeature, channelType),
|
||||
switchMap(([v, hasFeature, cType]) => {
|
||||
const shouldShowwithGMasDMBehavior = hasFeature && isTypeDMorGM(cType);
|
||||
|
||||
let defaultLevelToUse = v;
|
||||
if (shouldShowwithGMasDMBehavior) {
|
||||
if (v === NotificationLevel.MENTION) {
|
||||
defaultLevelToUse = NotificationLevel.ALL;
|
||||
}
|
||||
}
|
||||
|
||||
return of$(defaultLevelToUse);
|
||||
}),
|
||||
);
|
||||
|
||||
const defaultThreadReplies = notifyProps.pipe(
|
||||
switchMap((n) => of$(n?.push_threads)),
|
||||
);
|
||||
|
|
@ -47,6 +66,8 @@ const enhanced = withObservables([], ({channelId, database}: EnhancedProps) => {
|
|||
notifyThreadReplies,
|
||||
defaultLevel,
|
||||
defaultThreadReplies,
|
||||
channelType,
|
||||
hasGMasDMFeature,
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ const NOTIFY_OPTIONS: Record<string, NotifPrefOptions> = {
|
|||
value: NotificationLevel.ALL,
|
||||
},
|
||||
[NotificationLevel.MENTION]: {
|
||||
defaultMessage: 'Mentions, direct messages only',
|
||||
defaultMessage: 'Mentions only',
|
||||
id: t('channel_notification_preferences.notification.mention'),
|
||||
testID: 'channel_notification_preferences.notification.mention',
|
||||
value: NotificationLevel.MENTION,
|
||||
|
|
@ -53,7 +53,13 @@ const NOTIFY_OPTIONS: Record<string, NotifPrefOptions> = {
|
|||
},
|
||||
};
|
||||
|
||||
const NotifyAbout = ({defaultLevel, isMuted, notifyLevel, notifyTitleTop, onPress}: Props) => {
|
||||
const NotifyAbout = ({
|
||||
defaultLevel,
|
||||
isMuted,
|
||||
notifyLevel,
|
||||
notifyTitleTop,
|
||||
onPress,
|
||||
}: Props) => {
|
||||
const {formatMessage} = useIntl();
|
||||
const onLayout = useCallback((e: LayoutChangeEvent) => {
|
||||
const {y} = e.nativeEvent.layout;
|
||||
|
|
@ -61,6 +67,11 @@ const NotifyAbout = ({defaultLevel, isMuted, notifyLevel, notifyTitleTop, onPres
|
|||
notifyTitleTop.value = y > 0 ? y + 10 : BLOCK_TITLE_HEIGHT;
|
||||
}, []);
|
||||
|
||||
let notifyLevelToUse = notifyLevel;
|
||||
if (notifyLevel === NotificationLevel.DEFAULT) {
|
||||
notifyLevelToUse = defaultLevel;
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingBlock
|
||||
headerText={NOTIFY_ABOUT}
|
||||
|
|
@ -77,7 +88,7 @@ const NotifyAbout = ({defaultLevel, isMuted, notifyLevel, notifyTitleTop, onPres
|
|||
<SettingOption
|
||||
action={onPress}
|
||||
label={label}
|
||||
selected={notifyLevel === key}
|
||||
selected={notifyLevelToUse === key}
|
||||
testID={testID}
|
||||
type='select'
|
||||
value={value}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ const NOTIFY_OPTIONS_THREAD: Record<string, NotifPrefOptions> = {
|
|||
const NotifyAbout = ({isSelected, notifyLevel, onPress}: Props) => {
|
||||
const {formatMessage} = useIntl();
|
||||
|
||||
if ([NotificationLevel.NONE, NotificationLevel.ALL].includes(notifyLevel)) {
|
||||
const hiddenStates: NotificationLevel[] = [NotificationLevel.NONE, NotificationLevel.ALL];
|
||||
if (hiddenStates.includes(notifyLevel)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -73,19 +73,24 @@ 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>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ const MobileSendPush = ({sendPushNotifications, pushStatus, setMobilePushPref}:
|
|||
<SettingSeparator/>
|
||||
<SettingOption
|
||||
action={setMobilePushPref}
|
||||
label={intl.formatMessage({id: 'notification_settings.pushNotification.mentions_only', defaultMessage: 'Mentions, direct messages only (default)'})}
|
||||
label={intl.formatMessage({id: 'notification_settings.pushNotification.mentions_only', defaultMessage: 'Only for mentions, direct messages and group messages (default)'})}
|
||||
selected={pushStatus === 'mention'}
|
||||
testID='push_notification_settings.mentions_only.option'
|
||||
type='select'
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ class EphemeralStore {
|
|||
creatingChannel = false;
|
||||
creatingDMorGMTeammates: string[] = [];
|
||||
|
||||
noticeShown = new Set<string>();
|
||||
|
||||
private pushProxyVerification: {[serverUrl: string]: string | undefined} = {};
|
||||
private canJoinOtherTeams: {[serverUrl: string]: BehaviorSubject<boolean>} = {};
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ const ShareModule: NativeShareExtension|undefined = Platform.select({android: Na
|
|||
// versions, and a non-equal minor version will ignore dot version.
|
||||
// currentVersion is a string, e.g '4.6.0'
|
||||
// minMajorVersion, minMinorVersion, minDotVersion are integers
|
||||
export const isMinimumServerVersion = (currentVersion: string, minMajorVersion = 0, minMinorVersion = 0, minDotVersion = 0): boolean => {
|
||||
export const isMinimumServerVersion = (currentVersion = '', minMajorVersion = 0, minMinorVersion = 0, minDotVersion = 0): boolean => {
|
||||
if (!currentVersion || typeof currentVersion !== 'string') {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@
|
|||
"channel_notification_preferences.muted_content": "You can change the notification settings, but you will not receive notifications until the channel is unmuted.",
|
||||
"channel_notification_preferences.muted_title": "This channel is muted",
|
||||
"channel_notification_preferences.notification.all": "All new messages",
|
||||
"channel_notification_preferences.notification.mention": "Mentions, direct messages only",
|
||||
"channel_notification_preferences.notification.mention": "Mentions only",
|
||||
"channel_notification_preferences.notification.none": "Nothing",
|
||||
"channel_notification_preferences.notification.thread_replies": "Notify me about replies to threads I’m following in this channel",
|
||||
"channel_notification_preferences.notify_about": "Notify me about...",
|
||||
|
|
@ -341,6 +341,7 @@
|
|||
"intro.created_by": "created by {creator} on {date}.",
|
||||
"intro.direct_message": "This is the start of your conversation with {teammate}. Messages and files shared here are not shown to anyone else.",
|
||||
"intro.group_message": "This is the start of your conversation with this group. Messages and files shared here are not shown to anyone else outside of the group.",
|
||||
"intro.group_message.after_gm_as_dm": "This is the start of your conversation with this group. Messages and files shared here are not shown to anyone else outside of the group.",
|
||||
"intro.private_channel": "Private Channel",
|
||||
"intro.public_channel": "Public Channel",
|
||||
"intro.townsquare": "Welcome to {name}. Everyone automatically becomes a member of this channel when they join the team.",
|
||||
|
|
@ -765,7 +766,7 @@
|
|||
"notification_settings.push_threads.replies": "Thread replies",
|
||||
"notification_settings.pushNotification.all_new_messages": "All new messages",
|
||||
"notification_settings.pushNotification.disabled_long": "Push notifications for mobile devices have been disabled by your System Administrator.",
|
||||
"notification_settings.pushNotification.mentions_only": "Mentions, direct messages only (default)",
|
||||
"notification_settings.pushNotification.mentions_only": "Only for mentions, direct messages and group messages (default)",
|
||||
"notification_settings.pushNotification.nothing": "Nothing",
|
||||
"notification_settings.send_notification.about": "Notify me about...",
|
||||
"notification_settings.threads_mentions": "Mentions in threads",
|
||||
|
|
@ -1016,6 +1017,10 @@
|
|||
"suggestion.search.direct": "Direct Messages",
|
||||
"suggestion.search.private": "Private Channels",
|
||||
"suggestion.search.public": "Public Channels",
|
||||
"system_notice.dont_show": "Don't Show Again",
|
||||
"system_notice.remind_me": "Remind Me Later",
|
||||
"system_notice.title.gm_as_dm": "Updates to Group Messages",
|
||||
"system_noticy.body.gm_as_dm": "You will now be notified for all activity in your group messages along with a notification badge for every new message.\n\nYou can configure this in notification preferences for each group message.",
|
||||
"team_list.no_other_teams.description": "To join another team, ask a Team Admin for an invitation, or create your own team.",
|
||||
"team_list.no_other_teams.title": "No additional teams to join",
|
||||
"terms_of_service.acceptButton": "Accept",
|
||||
|
|
|
|||
Loading…
Reference in a new issue