Notification: Respect global notification settings and exceptions (#1123)
This commit is contained in:
parent
839b6b65f2
commit
33aaad6bca
@ -3,9 +3,8 @@ import { ApiUser, ApiUserStatus, ApiUserType } from '../../types';
|
||||
|
||||
export function buildApiUserFromFull(mtpUserFull: GramJs.UserFull): ApiUser {
|
||||
const {
|
||||
about, commonChatsCount, pinnedMsgId, botInfo, notifySettings: { silent, muteUntil },
|
||||
about, commonChatsCount, pinnedMsgId, botInfo,
|
||||
} = mtpUserFull;
|
||||
const isMuted = silent || (typeof muteUntil === 'number' && Date.now() < muteUntil * 1000);
|
||||
|
||||
return {
|
||||
...(buildApiUser(mtpUserFull.user) as ApiUser),
|
||||
@ -13,7 +12,6 @@ export function buildApiUserFromFull(mtpUserFull: GramJs.UserFull): ApiUser {
|
||||
bio: about,
|
||||
commonChatsCount,
|
||||
pinnedMessageId: pinnedMsgId,
|
||||
isMuted,
|
||||
...(botInfo && { botDescription: botInfo.description }),
|
||||
},
|
||||
};
|
||||
|
||||
@ -45,7 +45,7 @@ export {
|
||||
updateProfile, checkUsername, updateUsername, fetchBlockedContacts, blockContact, unblockContact,
|
||||
updateProfilePhoto, uploadProfilePhoto, fetchWallpapers, uploadWallpaper,
|
||||
fetchAuthorizations, terminateAuthorization, terminateAllAuthorizations,
|
||||
loadNotificationsSettings, updateContactSignUpNotification, updateNotificationSettings,
|
||||
fetchNotificationExceptions, fetchNotificationSettings, updateContactSignUpNotification, updateNotificationSettings,
|
||||
fetchLanguages, fetchLangPack, fetchPrivacySettings, setPrivacySettings, registerDevice, unregisterDevice,
|
||||
} from './settings';
|
||||
|
||||
|
||||
@ -156,7 +156,15 @@ export function terminateAllAuthorizations() {
|
||||
return invokeRequest(new GramJs.auth.ResetAuthorizations());
|
||||
}
|
||||
|
||||
export async function loadNotificationsSettings() {
|
||||
export async function fetchNotificationExceptions() {
|
||||
const result = await invokeRequest(new GramJs.account.GetNotifyExceptions({ compareSound: true }), true);
|
||||
|
||||
if (result instanceof GramJs.Updates || result instanceof GramJs.UpdatesCombined) {
|
||||
updateLocalDb(result);
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchNotificationSettings() {
|
||||
const [
|
||||
isMutedContactSignUpNotification,
|
||||
privateContactNotificationsSettings,
|
||||
@ -212,10 +220,10 @@ export function updateContactSignUpNotification(isSilent: boolean) {
|
||||
|
||||
export function updateNotificationSettings(peerType: 'contact' | 'group' | 'broadcast', {
|
||||
isSilent,
|
||||
isShowPreviews,
|
||||
shouldShowPreviews,
|
||||
}: {
|
||||
isSilent: boolean;
|
||||
isShowPreviews: boolean;
|
||||
shouldShowPreviews: boolean;
|
||||
}) {
|
||||
let peer: GramJs.TypeInputNotifyPeer;
|
||||
if (peerType === 'contact') {
|
||||
@ -227,7 +235,7 @@ export function updateNotificationSettings(peerType: 'contact' | 'group' | 'broa
|
||||
}
|
||||
|
||||
const settings = {
|
||||
showPreviews: isShowPreviews,
|
||||
showPreviews: shouldShowPreviews,
|
||||
silent: isSilent,
|
||||
muteUntil: isSilent ? MAX_INT_32 : undefined,
|
||||
};
|
||||
@ -358,7 +366,10 @@ export async function setPrivacySettings(
|
||||
return buildPrivacyRules(result.rules);
|
||||
}
|
||||
|
||||
function updateLocalDb(result: GramJs.account.PrivacyRules | GramJs.contacts.Blocked | GramJs.contacts.BlockedSlice) {
|
||||
function updateLocalDb(
|
||||
result: GramJs.account.PrivacyRules | GramJs.contacts.Blocked | GramJs.contacts.BlockedSlice |
|
||||
GramJs.Updates | GramJs.UpdatesCombined,
|
||||
) {
|
||||
result.users.forEach((user) => {
|
||||
if (user instanceof GramJs.User) {
|
||||
localDb.users[user.id] = user;
|
||||
|
||||
@ -544,14 +544,18 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
|
||||
update instanceof GramJs.UpdateNotifySettings
|
||||
&& update.peer instanceof GramJs.NotifyPeer
|
||||
) {
|
||||
const { silent, muteUntil } = update.notifySettings;
|
||||
const {
|
||||
silent, muteUntil, showPreviews, sound,
|
||||
} = update.notifySettings;
|
||||
|
||||
const isMuted = silent || (typeof muteUntil === 'number' && Date.now() < muteUntil * 1000);
|
||||
|
||||
onUpdate({
|
||||
'@type': 'updateChat',
|
||||
'@type': 'updateNotifyExceptions',
|
||||
id: getApiChatIdFromMtpPeer(update.peer.peer),
|
||||
chat: {
|
||||
isMuted: silent || (typeof muteUntil === 'number' && Date.now() < muteUntil * 1000),
|
||||
},
|
||||
isMuted,
|
||||
...(sound === '' && { isSilent: true }),
|
||||
...(showPreviews !== undefined && { shouldShowPreviews: Boolean(showPreviews) }),
|
||||
});
|
||||
} else if (
|
||||
update instanceof GramJs.UpdateUserTyping
|
||||
@ -741,7 +745,7 @@ export function updater(update: Update, originRequest?: GramJs.AnyRequest) {
|
||||
'@type': 'updateNotifySettings',
|
||||
peerType,
|
||||
isSilent: Boolean(silent || (typeof muteUntil === 'number' && Date.now() < muteUntil * 1000)),
|
||||
isShowPreviews: Boolean(showPreviews),
|
||||
shouldShowPreviews: Boolean(showPreviews),
|
||||
});
|
||||
} else if (update instanceof GramJs.UpdatePeerBlocked) {
|
||||
onUpdate({
|
||||
|
||||
@ -327,7 +327,15 @@ export type ApiUpdateNotifySettings = {
|
||||
'@type': 'updateNotifySettings';
|
||||
peerType: 'contact' | 'group' | 'broadcast';
|
||||
isSilent: boolean;
|
||||
isShowPreviews: boolean;
|
||||
shouldShowPreviews: boolean;
|
||||
};
|
||||
|
||||
export type ApiUpdateNotifyExceptions = {
|
||||
'@type': 'updateNotifyExceptions';
|
||||
id: number;
|
||||
isMuted: boolean;
|
||||
isSilent?: boolean;
|
||||
shouldShowPreviews?: boolean;
|
||||
};
|
||||
|
||||
export type updateTwoFaStateWaitCode = {
|
||||
@ -369,7 +377,7 @@ export type ApiUpdate = (
|
||||
ApiUpdateNewScheduledMessage | ApiUpdateScheduledMessageSendSucceeded | ApiUpdateScheduledMessage |
|
||||
ApiUpdateDeleteScheduledMessages | ApiUpdateResetMessages |
|
||||
ApiUpdateTwoFaError | updateTwoFaStateWaitCode |
|
||||
ApiUpdateNotifySettings | ApiUpdatePeerBlocked | ApiUpdatePrivacy
|
||||
ApiUpdateNotifySettings | ApiUpdateNotifyExceptions | ApiUpdatePeerBlocked | ApiUpdatePrivacy
|
||||
);
|
||||
|
||||
export type OnApiUpdate = (update: ApiUpdate) => void;
|
||||
|
||||
@ -25,7 +25,6 @@ export interface ApiUserFullInfo {
|
||||
commonChatsCount?: number;
|
||||
botDescription?: string;
|
||||
pinnedMessageId?: number;
|
||||
isMuted?: boolean;
|
||||
}
|
||||
|
||||
export type ApiUserType = 'userTypeBot' | 'userTypeRegular' | 'userTypeDeleted' | 'userTypeUnknown';
|
||||
|
||||
@ -12,13 +12,14 @@ import './Badge.scss';
|
||||
type OwnProps = {
|
||||
chat: ApiChat;
|
||||
isPinned?: boolean;
|
||||
isMuted?: boolean;
|
||||
};
|
||||
|
||||
const Badge: FC<OwnProps> = ({ chat, isPinned }) => {
|
||||
const Badge: FC<OwnProps> = ({ chat, isPinned, isMuted }) => {
|
||||
const isShown = Boolean(chat.unreadCount || chat.hasUnreadMark || isPinned);
|
||||
const className = buildClassName(
|
||||
'Badge',
|
||||
chat.isMuted && 'muted',
|
||||
isMuted && 'muted',
|
||||
isPinned && 'pinned',
|
||||
Boolean(chat.unreadCount || chat.hasUnreadMark) && 'unread',
|
||||
);
|
||||
|
||||
@ -25,9 +25,11 @@ import {
|
||||
getMessageMediaThumbDataUri,
|
||||
getMessageVideo,
|
||||
getMessageSticker,
|
||||
selectIsChatMuted,
|
||||
} from '../../../modules/helpers';
|
||||
import {
|
||||
selectChat, selectUser, selectChatMessage, selectOutgoingStatus, selectDraft, selectCurrentMessageList,
|
||||
selectNotifySettings, selectNotifyExceptions,
|
||||
} from '../../../modules/selectors';
|
||||
import { renderActionMessageText } from '../../common/helpers/renderActionMessageText';
|
||||
import renderText from '../../common/helpers/renderText';
|
||||
@ -62,6 +64,7 @@ type OwnProps = {
|
||||
|
||||
type StateProps = {
|
||||
chat?: ApiChat;
|
||||
isMuted?: boolean;
|
||||
privateChatUser?: ApiUser;
|
||||
actionTargetUser?: ApiUser;
|
||||
actionTargetMessage?: ApiMessage;
|
||||
@ -87,6 +90,7 @@ const Chat: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
isSelected,
|
||||
isPinned,
|
||||
chat,
|
||||
isMuted,
|
||||
privateChatUser,
|
||||
actionTargetUser,
|
||||
lastMessageSender,
|
||||
@ -255,14 +259,14 @@ const Chat: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
<div className="title">
|
||||
<h3>{renderText(getChatTitle(chat, privateChatUser))}</h3>
|
||||
{chat.isVerified && <VerifiedIcon />}
|
||||
{chat.isMuted && <i className="icon-muted-chat" />}
|
||||
{isMuted && <i className="icon-muted-chat" />}
|
||||
{chat.lastMessage && (
|
||||
<LastMessageMeta message={chat.lastMessage} outgoingStatus={lastMessageOutgoingStatus} />
|
||||
)}
|
||||
</div>
|
||||
<div className="subtitle">
|
||||
{renderLastMessageOrTyping()}
|
||||
<Badge chat={chat} isPinned={isPinned} />
|
||||
<Badge chat={chat} isPinned={isPinned} isMuted={isMuted} />
|
||||
</div>
|
||||
</div>
|
||||
<DeleteChatModal
|
||||
@ -307,6 +311,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
|
||||
return {
|
||||
chat,
|
||||
isMuted: selectIsChatMuted(chat, selectNotifySettings(global), selectNotifyExceptions(global)),
|
||||
lastMessageSender,
|
||||
...(isOutgoing && { lastMessageOutgoingStatus: selectOutgoingStatus(global, chat.lastMessage) }),
|
||||
...(privateChatUserId && { privateChatUser: selectUser(global, privateChatUserId) }),
|
||||
|
||||
@ -5,11 +5,13 @@ import { withGlobal } from '../../../lib/teact/teactn';
|
||||
|
||||
import { ApiChat, ApiChatFolder, ApiUser } from '../../../api/types';
|
||||
import { GlobalActions } from '../../../global/types';
|
||||
import { NotifyException, NotifySettings } from '../../../types';
|
||||
|
||||
import { IS_TOUCH_ENV } from '../../../util/environment';
|
||||
import { buildCollectionByKey, pick } from '../../../util/iteratees';
|
||||
import { captureEvents, SwipeDirection } from '../../../util/captureEvents';
|
||||
import { getFolderUnreadDialogs } from '../../../modules/helpers';
|
||||
import { selectNotifyExceptions, selectNotifySettings } from '../../../modules/selectors';
|
||||
import useShowTransition from '../../../hooks/useShowTransition';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
import useThrottledMemo from '../../../hooks/useThrottledMemo';
|
||||
@ -24,6 +26,8 @@ type StateProps = {
|
||||
chatsById: Record<number, ApiChat>;
|
||||
usersById: Record<number, ApiUser>;
|
||||
chatFoldersById: Record<number, ApiChatFolder>;
|
||||
notifySettings: NotifySettings;
|
||||
notifyExceptions: Record<number, NotifyException>;
|
||||
orderedFolderIds?: number[];
|
||||
lastSyncTime?: number;
|
||||
};
|
||||
@ -36,6 +40,8 @@ const ChatFolders: FC<StateProps & DispatchProps> = ({
|
||||
chatsById,
|
||||
usersById,
|
||||
chatFoldersById,
|
||||
notifySettings,
|
||||
notifyExceptions,
|
||||
orderedFolderIds,
|
||||
lastSyncTime,
|
||||
loadChatFolders,
|
||||
@ -68,7 +74,7 @@ const ChatFolders: FC<StateProps & DispatchProps> = ({
|
||||
const counters = displayedFolders.map((folder) => {
|
||||
const {
|
||||
unreadDialogsCount, hasActiveDialogs,
|
||||
} = getFolderUnreadDialogs(chatsById, usersById, folder, chatIds) || {};
|
||||
} = getFolderUnreadDialogs(chatsById, usersById, folder, notifySettings, notifyExceptions, chatIds) || {};
|
||||
|
||||
return {
|
||||
id: folder.id,
|
||||
@ -78,7 +84,7 @@ const ChatFolders: FC<StateProps & DispatchProps> = ({
|
||||
});
|
||||
|
||||
return buildCollectionByKey(counters, 'id');
|
||||
}, INFO_THROTTLE, [displayedFolders, chatsById, usersById]);
|
||||
}, INFO_THROTTLE, [displayedFolders, chatsById, usersById, notifySettings, notifyExceptions]);
|
||||
|
||||
const folderTabs = useMemo(() => {
|
||||
if (!displayedFolders || !displayedFolders.length) {
|
||||
@ -185,6 +191,8 @@ export default memo(withGlobal(
|
||||
chatFoldersById,
|
||||
orderedFolderIds,
|
||||
lastSyncTime,
|
||||
notifySettings: selectNotifySettings(global),
|
||||
notifyExceptions: selectNotifyExceptions(global),
|
||||
};
|
||||
},
|
||||
(setGlobal, actions): DispatchProps => pick(actions, ['loadChatFolders']),
|
||||
|
||||
@ -7,13 +7,16 @@ import { GlobalActions } from '../../../global/types';
|
||||
import {
|
||||
ApiChat, ApiChatFolder, ApiUser, MAIN_THREAD_ID,
|
||||
} from '../../../api/types';
|
||||
import { NotifyException, NotifySettings } from '../../../types';
|
||||
|
||||
import { ALL_CHATS_PRELOAD_DISABLED, CHAT_HEIGHT_PX, CHAT_LIST_SLICE } from '../../../config';
|
||||
import { IS_ANDROID } from '../../../util/environment';
|
||||
import usePrevious from '../../../hooks/usePrevious';
|
||||
import { mapValues, pick } from '../../../util/iteratees';
|
||||
import { getChatOrder, prepareChatList, prepareFolderListIds } from '../../../modules/helpers';
|
||||
import { selectChatFolder, selectCurrentMessageList } from '../../../modules/selectors';
|
||||
import {
|
||||
selectChatFolder, selectCurrentMessageList, selectNotifyExceptions, selectNotifySettings,
|
||||
} from '../../../modules/selectors';
|
||||
import useInfiniteScroll from '../../../hooks/useInfiniteScroll';
|
||||
import { useChatAnimationType } from './hooks';
|
||||
|
||||
@ -36,6 +39,8 @@ type StateProps = {
|
||||
orderedPinnedIds?: number[];
|
||||
lastSyncTime?: number;
|
||||
isInDiscussionThread?: boolean;
|
||||
notifySettings: NotifySettings;
|
||||
notifyExceptions: Record<number, NotifyException>;
|
||||
};
|
||||
|
||||
type DispatchProps = Pick<GlobalActions, 'loadMoreChats' | 'preloadTopChatMessages'>;
|
||||
@ -57,14 +62,16 @@ const ChatList: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
orderedPinnedIds,
|
||||
lastSyncTime,
|
||||
isInDiscussionThread,
|
||||
notifySettings,
|
||||
notifyExceptions,
|
||||
loadMoreChats,
|
||||
preloadTopChatMessages,
|
||||
}) => {
|
||||
const [currentListIds, currentPinnedIds] = useMemo(() => {
|
||||
return folderType === 'folder' && chatFolder
|
||||
? prepareFolderListIds(chatsById, usersById, chatFolder)
|
||||
? prepareFolderListIds(chatsById, usersById, chatFolder, notifySettings, notifyExceptions)
|
||||
: [listIds, orderedPinnedIds];
|
||||
}, [folderType, chatsById, usersById, chatFolder, listIds, orderedPinnedIds]);
|
||||
}, [folderType, chatFolder, chatsById, usersById, notifySettings, notifyExceptions, listIds, orderedPinnedIds]);
|
||||
|
||||
const [orderById, orderedIds] = useMemo(() => {
|
||||
if (!currentListIds || (folderType === 'folder' && !chatFolder)) {
|
||||
@ -202,6 +209,8 @@ export default memo(withGlobal<OwnProps>(
|
||||
chatFolder,
|
||||
}),
|
||||
isInDiscussionThread: currentThreadId !== MAIN_THREAD_ID,
|
||||
notifySettings: selectNotifySettings(global),
|
||||
notifyExceptions: selectNotifyExceptions(global),
|
||||
};
|
||||
},
|
||||
(setGlobal, actions): DispatchProps => pick(actions, ['loadMoreChats', 'preloadTopChatMessages']),
|
||||
|
||||
@ -22,7 +22,7 @@ type StateProps = {
|
||||
};
|
||||
|
||||
type DispatchProps = Pick<GlobalActions, (
|
||||
'loadNotificationsSettings' | 'updateContactSignUpNotification' | 'updateNotificationSettings'
|
||||
'loadNotificationSettings' | 'updateContactSignUpNotification' | 'updateNotificationSettings'
|
||||
)>;
|
||||
|
||||
const SettingsNotifications: FC<StateProps & DispatchProps> = ({
|
||||
@ -33,13 +33,13 @@ const SettingsNotifications: FC<StateProps & DispatchProps> = ({
|
||||
hasBroadcastNotifications,
|
||||
hasBroadcastMessagePreview,
|
||||
hasContactJoinedNotifications,
|
||||
loadNotificationsSettings,
|
||||
loadNotificationSettings,
|
||||
updateContactSignUpNotification,
|
||||
updateNotificationSettings,
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
loadNotificationsSettings();
|
||||
}, [loadNotificationsSettings]);
|
||||
loadNotificationSettings();
|
||||
}, [loadNotificationSettings]);
|
||||
|
||||
const handleSettingsChange = useCallback((
|
||||
e: ChangeEvent<HTMLInputElement>,
|
||||
@ -49,14 +49,14 @@ const SettingsNotifications: FC<StateProps & DispatchProps> = ({
|
||||
const currentIsSilent = peerType === 'contact'
|
||||
? !hasPrivateChatsNotifications
|
||||
: !(peerType === 'group' ? hasGroupNotifications : hasBroadcastNotifications);
|
||||
const currentIsShowPreviews = peerType === 'contact'
|
||||
const currentShouldShowPreviews = peerType === 'contact'
|
||||
? hasPrivateChatsMessagePreview
|
||||
: (peerType === 'group' ? hasGroupMessagePreview : hasBroadcastMessagePreview);
|
||||
|
||||
updateNotificationSettings({
|
||||
peerType,
|
||||
...(setting === 'silent' && { isSilent: !e.target.checked, isShowPreviews: currentIsShowPreviews }),
|
||||
...(setting === 'showPreviews' && { isShowPreviews: e.target.checked, isSilent: currentIsSilent }),
|
||||
...(setting === 'silent' && { isSilent: !e.target.checked, shouldShowPreviews: currentShouldShowPreviews }),
|
||||
...(setting === 'showPreviews' && { shouldShowPreviews: e.target.checked, isSilent: currentIsSilent }),
|
||||
});
|
||||
}, [
|
||||
hasBroadcastMessagePreview, hasBroadcastNotifications,
|
||||
@ -151,7 +151,7 @@ export default memo(withGlobal((global): StateProps => {
|
||||
};
|
||||
},
|
||||
(setGlobal, actions): DispatchProps => pick(actions, [
|
||||
'loadNotificationsSettings',
|
||||
'loadNotificationSettings',
|
||||
'updateContactSignUpNotification',
|
||||
'updateNotificationSettings',
|
||||
]))(SettingsNotifications));
|
||||
|
||||
@ -5,9 +5,11 @@ import { withGlobal } from '../../../../lib/teact/teactn';
|
||||
|
||||
import { GlobalActions } from '../../../../global/types';
|
||||
import { ApiChatFolder, ApiChat, ApiUser } from '../../../../api/types';
|
||||
import { NotifyException, NotifySettings } from '../../../../types';
|
||||
|
||||
import { STICKER_SIZE_FOLDER_SETTINGS } from '../../../../config';
|
||||
import { pick } from '../../../../util/iteratees';
|
||||
import { selectNotifyExceptions, selectNotifySettings } from '../../../../modules/selectors';
|
||||
import { throttle } from '../../../../util/schedulers';
|
||||
import getAnimationData from '../../../common/helpers/animatedAssets';
|
||||
import { getFolderDescriptionText } from '../../../../modules/helpers';
|
||||
@ -29,6 +31,8 @@ type StateProps = {
|
||||
orderedFolderIds?: number[];
|
||||
foldersById: Record<number, ApiChatFolder>;
|
||||
recommendedChatFolders?: ApiChatFolder[];
|
||||
notifySettings: NotifySettings;
|
||||
notifyExceptions: Record<number, NotifyException>;
|
||||
};
|
||||
|
||||
type DispatchProps = Pick<GlobalActions, 'loadRecommendedChatFolders' | 'addChatFolder' | 'showError'>;
|
||||
@ -45,6 +49,8 @@ const SettingsFoldersMain: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
orderedFolderIds,
|
||||
foldersById,
|
||||
recommendedChatFolders,
|
||||
notifySettings,
|
||||
notifyExceptions,
|
||||
loadRecommendedChatFolders,
|
||||
addChatFolder,
|
||||
showError,
|
||||
@ -96,10 +102,12 @@ const SettingsFoldersMain: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
return {
|
||||
id: folder.id,
|
||||
title: folder.title,
|
||||
subtitle: getFolderDescriptionText(chatsById, usersById, folder, chatIds, lang),
|
||||
subtitle: getFolderDescriptionText(
|
||||
chatsById, usersById, folder, notifySettings, notifyExceptions, chatIds, lang,
|
||||
),
|
||||
};
|
||||
});
|
||||
}, [orderedFolderIds, chatsById, foldersById, usersById, lang]);
|
||||
}, [orderedFolderIds, chatsById, foldersById, usersById, notifySettings, notifyExceptions, lang]);
|
||||
|
||||
const handleCreateFolderFromRecommended = useCallback((folder: ApiChatFolder) => {
|
||||
if (Object.keys(foldersById).length >= MAX_ALLOWED_FOLDERS) {
|
||||
@ -222,6 +230,8 @@ export default memo(withGlobal<OwnProps>(
|
||||
orderedFolderIds,
|
||||
foldersById,
|
||||
recommendedChatFolders,
|
||||
notifySettings: selectNotifySettings(global),
|
||||
notifyExceptions: selectNotifyExceptions(global),
|
||||
};
|
||||
},
|
||||
(setGlobal, actions): DispatchProps => pick(actions, ['loadRecommendedChatFolders', 'addChatFolder', 'showError']),
|
||||
|
||||
@ -209,5 +209,6 @@ function reduceSettings(global: GlobalState): GlobalState['settings'] {
|
||||
return {
|
||||
byKey,
|
||||
privacy: {},
|
||||
notifyExceptions: {},
|
||||
};
|
||||
}
|
||||
|
||||
@ -116,6 +116,7 @@ export const INITIAL_STATE: GlobalState = {
|
||||
language: 'en',
|
||||
},
|
||||
privacy: {},
|
||||
notifyExceptions: {},
|
||||
},
|
||||
|
||||
twoFaSettings: {},
|
||||
|
||||
@ -34,6 +34,7 @@ import {
|
||||
Receipt,
|
||||
ApiPrivacyKey,
|
||||
ApiPrivacySettings,
|
||||
NotifyException,
|
||||
} from '../types';
|
||||
|
||||
export type MessageListType = 'thread' | 'pinned' | 'scheduled';
|
||||
@ -365,6 +366,7 @@ export type GlobalState = {
|
||||
byKey: ISettings;
|
||||
loadedWallpapers?: ApiWallpaper[];
|
||||
privacy: Partial<Record<ApiPrivacyKey, ApiPrivacySettings>>;
|
||||
notifyExceptions: Record<number, NotifyException>;
|
||||
};
|
||||
|
||||
twoFaSettings: {
|
||||
@ -434,8 +436,9 @@ export type ActionTypes = (
|
||||
'updatePassword' | 'updateRecoveryEmail' | 'clearPassword' | 'provideTwoFaEmailCode' | 'checkPassword' |
|
||||
'loadBlockedContacts' | 'blockContact' | 'unblockContact' |
|
||||
'loadAuthorizations' | 'terminateAuthorization' | 'terminateAllAuthorizations' |
|
||||
'loadNotificationsSettings' | 'updateContactSignUpNotification' | 'updateNotificationSettings' |
|
||||
'loadNotificationSettings' | 'updateContactSignUpNotification' | 'updateNotificationSettings' |
|
||||
'loadLanguages' | 'loadPrivacySettings' | 'setPrivacyVisibility' | 'setPrivacySettings' |
|
||||
'loadNotificationExceptions' |
|
||||
// Stickers & GIFs
|
||||
'loadStickerSets' | 'loadAddedStickers' | 'loadRecentStickers' | 'loadFavoriteStickers' | 'loadFeaturedStickers' |
|
||||
'loadStickers' | 'setStickerSearchQuery' | 'loadSavedGifs' | 'setGifSearchQuery' | 'searchMoreGifs' |
|
||||
|
||||
1132
src/lib/gramjs/tl/api.d.ts
vendored
1132
src/lib/gramjs/tl/api.d.ts
vendored
File diff suppressed because it is too large
Load Diff
@ -939,6 +939,7 @@ account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings =
|
||||
account.confirmPasswordEmail#8fdf1920 code:string = Bool;
|
||||
account.getContactSignUpNotification#9f07c728 = Bool;
|
||||
account.setContactSignUpNotification#cff43f61 silent:Bool = Bool;
|
||||
account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true peer:flags.0?InputNotifyPeer = Updates;
|
||||
account.uploadWallPaper#dd853661 file:InputFile mime_type:string settings:WallPaperSettings = WallPaper;
|
||||
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
|
||||
users.getFullUser#ca30a5b1 id:InputUser = UserFull;
|
||||
|
||||
@ -939,6 +939,7 @@ account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings =
|
||||
account.confirmPasswordEmail#8fdf1920 code:string = Bool;
|
||||
account.getContactSignUpNotification#9f07c728 = Bool;
|
||||
account.setContactSignUpNotification#cff43f61 silent:Bool = Bool;
|
||||
account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true peer:flags.0?InputNotifyPeer = Updates;
|
||||
account.uploadWallPaper#dd853661 file:InputFile mime_type:string settings:WallPaperSettings = WallPaper;
|
||||
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
|
||||
users.getFullUser#ca30a5b1 id:InputUser = UserFull;
|
||||
|
||||
@ -304,9 +304,13 @@ addReducer('terminateAllAuthorizations', () => {
|
||||
})();
|
||||
});
|
||||
|
||||
addReducer('loadNotificationsSettings', () => {
|
||||
addReducer('loadNotificationExceptions', () => {
|
||||
callApi('fetchNotificationExceptions');
|
||||
});
|
||||
|
||||
addReducer('loadNotificationSettings', () => {
|
||||
(async () => {
|
||||
const result = await callApi('loadNotificationsSettings');
|
||||
const result = await callApi('fetchNotificationSettings');
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
@ -316,16 +320,16 @@ addReducer('loadNotificationsSettings', () => {
|
||||
});
|
||||
|
||||
addReducer('updateNotificationSettings', (global, actions, payload) => {
|
||||
const { peerType, isSilent, isShowPreviews } = payload!;
|
||||
const { peerType, isSilent, shouldShowPreviews } = payload!;
|
||||
|
||||
(async () => {
|
||||
const result = await callApi('updateNotificationSettings', peerType, { isSilent, isShowPreviews });
|
||||
const result = await callApi('updateNotificationSettings', peerType, { isSilent, shouldShowPreviews });
|
||||
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
|
||||
setGlobal(updateNotifySettings(getGlobal(), peerType, isSilent, isShowPreviews));
|
||||
setGlobal(updateNotifySettings(getGlobal(), peerType, isSilent, shouldShowPreviews));
|
||||
})();
|
||||
});
|
||||
|
||||
|
||||
@ -1,13 +1,27 @@
|
||||
import { addReducer } from '../../../lib/teact/teactn';
|
||||
import { addReducer, setGlobal } from '../../../lib/teact/teactn';
|
||||
|
||||
import { ApiUpdate } from '../../../api/types';
|
||||
import { GlobalState } from '../../../global/types';
|
||||
import { updateNotifySettings } from '../../reducers';
|
||||
import { addNotifyException, updateChat, updateNotifySettings } from '../../reducers';
|
||||
|
||||
addReducer('apiUpdate', (global, actions, update: ApiUpdate): GlobalState | undefined => {
|
||||
switch (update['@type']) {
|
||||
case 'updateNotifySettings': {
|
||||
return updateNotifySettings(global, update.peerType, update.isSilent, update.isShowPreviews);
|
||||
return updateNotifySettings(global, update.peerType, update.isSilent, update.shouldShowPreviews);
|
||||
}
|
||||
|
||||
case 'updateNotifyExceptions': {
|
||||
const {
|
||||
id, isMuted, isSilent, shouldShowPreviews,
|
||||
} = update;
|
||||
const chat = global.chats.byId[id];
|
||||
|
||||
if (chat) {
|
||||
global = updateChat(global, id, { isMuted });
|
||||
}
|
||||
|
||||
setGlobal(addNotifyException(global, id, { isMuted, isSilent, shouldShowPreviews }));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,6 +6,7 @@ import {
|
||||
ApiChatFolder,
|
||||
MAIN_THREAD_ID,
|
||||
} from '../../api/types';
|
||||
import { NotifyException, NotifySettings } from '../../types';
|
||||
|
||||
import { ARCHIVED_FOLDER_ID } from '../../config';
|
||||
import { orderBy } from '../../util/iteratees';
|
||||
@ -200,6 +201,17 @@ export function isChatArchived(chat: ApiChat) {
|
||||
return chat.folderId === ARCHIVED_FOLDER_ID;
|
||||
}
|
||||
|
||||
export function selectIsChatMuted(
|
||||
chat: ApiChat, notifySettings: NotifySettings, notifyExceptions: Record<number, NotifyException>,
|
||||
) {
|
||||
return !(notifyExceptions[chat.id] && !notifyExceptions[chat.id].isMuted) && (
|
||||
chat.isMuted
|
||||
|| (isChatPrivate(chat.id) && !notifySettings.hasPrivateChatsNotifications)
|
||||
|| (isChatChannel(chat) && !notifySettings.hasBroadcastNotifications)
|
||||
|| (isChatGroup(chat) && !notifySettings.hasGroupNotifications)
|
||||
);
|
||||
}
|
||||
|
||||
export function getCanDeleteChat(chat: ApiChat) {
|
||||
return isChatBasicGroup(chat) || ((isChatSuperGroup(chat) || isChatChannel(chat)) && chat.isCreator);
|
||||
}
|
||||
@ -208,6 +220,8 @@ export function prepareFolderListIds(
|
||||
chatsById: Record<number, ApiChat>,
|
||||
usersById: Record<number, ApiUser>,
|
||||
folder: ApiChatFolder,
|
||||
notifySettings: NotifySettings,
|
||||
notifyExceptions: Record<number, NotifyException>,
|
||||
chatIdsCache?: number[],
|
||||
) {
|
||||
const excludedChatIds = folder.excludedChatIds ? new Set(folder.excludedChatIds) : undefined;
|
||||
@ -216,7 +230,14 @@ export function prepareFolderListIds(
|
||||
const listIds = (chatIdsCache || Object.keys(chatsById).map(Number))
|
||||
.filter((id) => {
|
||||
return filterChatFolder(
|
||||
chatsById[id], folder, usersById, excludedChatIds, includedChatIds, pinnedChatIds,
|
||||
chatsById[id],
|
||||
folder,
|
||||
usersById,
|
||||
notifySettings,
|
||||
notifyExceptions,
|
||||
excludedChatIds,
|
||||
includedChatIds,
|
||||
pinnedChatIds,
|
||||
);
|
||||
});
|
||||
|
||||
@ -227,6 +248,8 @@ function filterChatFolder(
|
||||
chat: ApiChat,
|
||||
folder: ApiChatFolder,
|
||||
usersById: Record<number, ApiUser>,
|
||||
notifySettings: NotifySettings,
|
||||
notifyExceptions: Record<number, NotifyException>,
|
||||
excludedChatIds?: Set<number>,
|
||||
includedChatIds?: Set<number>,
|
||||
pinnedChatIds?: Set<number>,
|
||||
@ -247,7 +270,7 @@ function filterChatFolder(
|
||||
return false;
|
||||
}
|
||||
|
||||
if (chat.isMuted && folder.excludeMuted) {
|
||||
if (folder.excludeMuted && selectIsChatMuted(chat, notifySettings, notifyExceptions)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -340,9 +363,11 @@ export function getFolderUnreadDialogs(
|
||||
chatsById: Record<number, ApiChat>,
|
||||
usersById: Record<number, ApiUser>,
|
||||
folder: ApiChatFolder,
|
||||
notifySettings: NotifySettings,
|
||||
notifyExceptions: Record<number, NotifyException>,
|
||||
chatIdsCache: number[],
|
||||
) {
|
||||
const [listIds] = prepareFolderListIds(chatsById, usersById, folder, chatIdsCache);
|
||||
const [listIds] = prepareFolderListIds(chatsById, usersById, folder, notifySettings, notifyExceptions, chatIdsCache);
|
||||
|
||||
const listedChats = listIds
|
||||
.map((id) => chatsById[id])
|
||||
@ -366,6 +391,8 @@ export function getFolderDescriptionText(
|
||||
chatsById: Record<number, ApiChat>,
|
||||
usersById: Record<number, ApiUser>,
|
||||
folder: ApiChatFolder,
|
||||
notifySettings: NotifySettings,
|
||||
notifyExceptions: Record<number, NotifyException>,
|
||||
chatIdsCache: number[],
|
||||
lang: LangFn,
|
||||
) {
|
||||
@ -383,7 +410,7 @@ export function getFolderDescriptionText(
|
||||
|| (excludedChatIds && excludedChatIds.length)
|
||||
|| (includedChatIds && includedChatIds.length)
|
||||
) {
|
||||
const length = getFolderChatsCount(chatsById, usersById, folder, chatIdsCache);
|
||||
const length = getFolderChatsCount(chatsById, usersById, folder, notifySettings, notifyExceptions, chatIdsCache);
|
||||
return lang('Chats', length);
|
||||
}
|
||||
|
||||
@ -407,9 +434,13 @@ function getFolderChatsCount(
|
||||
chatsById: Record<number, ApiChat>,
|
||||
usersById: Record<number, ApiUser>,
|
||||
folder: ApiChatFolder,
|
||||
notifySettings: NotifySettings,
|
||||
notifyExceptions: Record<number, NotifyException>,
|
||||
chatIdsCache: number[],
|
||||
) {
|
||||
const [listIds, pinnedIds] = prepareFolderListIds(chatsById, usersById, folder, chatIdsCache);
|
||||
const [listIds, pinnedIds] = prepareFolderListIds(
|
||||
chatsById, usersById, folder, notifySettings, notifyExceptions, chatIdsCache,
|
||||
);
|
||||
const { pinnedChats, otherChats } = prepareChatList(chatsById, listIds, pinnedIds, 'folder');
|
||||
return pinnedChats.length + otherChats.length;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { GlobalState } from '../../global/types';
|
||||
import { ISettings } from '../../types';
|
||||
import { ISettings, NotifyException } from '../../types';
|
||||
|
||||
export function replaceSettings(global: GlobalState, newSettings?: Partial<ISettings>): GlobalState {
|
||||
return {
|
||||
@ -14,24 +14,39 @@ export function replaceSettings(global: GlobalState, newSettings?: Partial<ISett
|
||||
};
|
||||
}
|
||||
|
||||
export function addNotifyException(
|
||||
global: GlobalState, id: number, notifyException: NotifyException,
|
||||
): GlobalState {
|
||||
return {
|
||||
...global,
|
||||
settings: {
|
||||
...global.settings,
|
||||
notifyExceptions: {
|
||||
...global.settings.notifyExceptions,
|
||||
[id]: notifyException,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function updateNotifySettings(
|
||||
global: GlobalState, peerType: 'contact' | 'group' | 'broadcast', isSilent?: boolean, isShowPreviews?: boolean,
|
||||
global: GlobalState, peerType: 'contact' | 'group' | 'broadcast', isSilent?: boolean, shouldShowPreviews?: boolean,
|
||||
) {
|
||||
switch (peerType) {
|
||||
case 'contact':
|
||||
return replaceSettings(global, {
|
||||
...(typeof isSilent !== 'undefined' && { hasPrivateChatsNotifications: !isSilent }),
|
||||
...(typeof isShowPreviews !== 'undefined' && { hasPrivateChatsMessagePreview: isShowPreviews }),
|
||||
...(typeof shouldShowPreviews !== 'undefined' && { hasPrivateChatsMessagePreview: shouldShowPreviews }),
|
||||
});
|
||||
case 'group':
|
||||
return replaceSettings(global, {
|
||||
...(typeof isSilent !== 'undefined' && { hasGroupNotifications: !isSilent }),
|
||||
...(typeof isShowPreviews !== 'undefined' && { hasGroupMessagePreview: isShowPreviews }),
|
||||
...(typeof shouldShowPreviews !== 'undefined' && { hasGroupMessagePreview: shouldShowPreviews }),
|
||||
});
|
||||
case 'broadcast':
|
||||
return replaceSettings(global, {
|
||||
...(typeof isSilent !== 'undefined' && { hasBroadcastNotifications: !isSilent }),
|
||||
...(typeof isShowPreviews !== 'undefined' && { hasBroadcastMessagePreview: isShowPreviews }),
|
||||
...(typeof shouldShowPreviews !== 'undefined' && { hasBroadcastMessagePreview: shouldShowPreviews }),
|
||||
});
|
||||
|
||||
default:
|
||||
|
||||
@ -7,3 +7,4 @@ export * from './localSearch';
|
||||
export * from './management';
|
||||
export * from './symbols';
|
||||
export * from './payments';
|
||||
export * from './settings';
|
||||
|
||||
9
src/modules/selectors/settings.ts
Normal file
9
src/modules/selectors/settings.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { GlobalState } from '../../global/types';
|
||||
|
||||
export function selectNotifySettings(global: GlobalState) {
|
||||
return global.settings.byKey;
|
||||
}
|
||||
|
||||
export function selectNotifyExceptions(global: GlobalState) {
|
||||
return global.settings.notifyExceptions;
|
||||
}
|
||||
@ -20,7 +20,17 @@ export interface IAlbum {
|
||||
mainMessage: ApiMessage;
|
||||
}
|
||||
|
||||
export interface ISettings extends Record<string, any> {
|
||||
export type NotifySettings = {
|
||||
hasPrivateChatsNotifications?: boolean;
|
||||
hasPrivateChatsMessagePreview?: boolean;
|
||||
hasGroupNotifications?: boolean;
|
||||
hasGroupMessagePreview?: boolean;
|
||||
hasBroadcastNotifications?: boolean;
|
||||
hasBroadcastMessagePreview?: boolean;
|
||||
hasContactJoinedNotifications?: boolean;
|
||||
};
|
||||
|
||||
export interface ISettings extends NotifySettings, Record<string, any> {
|
||||
messageTextSize: number;
|
||||
customBackground?: string;
|
||||
patternColor?: string;
|
||||
@ -37,13 +47,6 @@ export interface ISettings extends Record<string, any> {
|
||||
shouldSuggestStickers: boolean;
|
||||
shouldLoopStickers: boolean;
|
||||
hasPassword?: boolean;
|
||||
hasPrivateChatsNotifications?: boolean;
|
||||
hasPrivateChatsMessagePreview?: boolean;
|
||||
hasGroupNotifications?: boolean;
|
||||
hasGroupMessagePreview?: boolean;
|
||||
hasBroadcastNotifications?: boolean;
|
||||
hasBroadcastMessagePreview?: boolean;
|
||||
hasContactJoinedNotifications?: boolean;
|
||||
languages?: ApiLanguage[];
|
||||
language: 'en' | 'fr' | 'de' | 'it' | 'pt' | 'ru' | 'es' | 'uk';
|
||||
}
|
||||
@ -269,3 +272,9 @@ export enum ManagementScreens {
|
||||
}
|
||||
|
||||
export type ManagementType = 'user' | 'group' | 'channel';
|
||||
|
||||
export type NotifyException = {
|
||||
isMuted: boolean;
|
||||
isSilent?: boolean;
|
||||
shouldShowPreviews?: boolean;
|
||||
};
|
||||
|
||||
@ -125,14 +125,18 @@ export async function unsubscribe() {
|
||||
}
|
||||
|
||||
// Load notification settings from the api
|
||||
async function loadNotificationsSettings() {
|
||||
const result = await callApi('loadNotificationsSettings');
|
||||
async function loadNotificationSettings() {
|
||||
const [result] = await Promise.all([
|
||||
callApi('fetchNotificationSettings'),
|
||||
callApi('fetchNotificationExceptions'),
|
||||
]);
|
||||
|
||||
if (!result) return;
|
||||
setGlobal(replaceSettings(getGlobal(), result));
|
||||
}
|
||||
|
||||
export async function subscribe() {
|
||||
loadNotificationsSettings();
|
||||
loadNotificationSettings();
|
||||
|
||||
if (!checkIfPushSupported()) {
|
||||
// Ask for notification permissions only if service worker notifications are not supported
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user