Settings: Add more privacy options and support (#3832)

This commit is contained in:
Alexander Zinchuk 2023-09-25 13:00:14 +02:00
parent acc962bcf5
commit 4efae0816c
30 changed files with 945 additions and 794 deletions

View File

@ -148,6 +148,7 @@ export function buildApiUsernames(mtpPeer: GramJs.User | GramJs.Channel | GramJs
export function buildPrivacyRules(rules: GramJs.TypePrivacyRule[]): ApiPrivacySettings {
let visibility: PrivacyVisibility | undefined;
let isUnspecified: boolean | undefined;
let allowUserIds: string[] | undefined;
let allowChatIds: string[] | undefined;
let blockUserIds: string[] | undefined;
@ -165,7 +166,6 @@ export function buildPrivacyRules(rules: GramJs.TypePrivacyRule[]): ApiPrivacySe
} else if (rule instanceof GramJs.PrivacyValueDisallowAll) {
visibility ||= 'nobody';
} else if (rule instanceof GramJs.PrivacyValueAllowUsers) {
visibility ||= 'selectedContacts';
allowUserIds = rule.users.map((chatId) => buildApiPeerId(chatId, 'user'));
} else if (rule instanceof GramJs.PrivacyValueDisallowUsers) {
blockUserIds = rule.users.map((chatId) => buildApiPeerId(chatId, 'user'));
@ -179,10 +179,12 @@ export function buildPrivacyRules(rules: GramJs.TypePrivacyRule[]): ApiPrivacySe
if (!visibility) {
// Disallow by default
visibility = 'nobody';
isUnspecified = true;
}
return {
visibility,
isUnspecified,
allowUserIds: allowUserIds || [],
allowChatIds: allowChatIds || [],
blockUserIds: blockUserIds || [],

View File

@ -64,6 +64,8 @@ export function buildPrivacyKey(key: GramJs.TypePrivacyKey): ApiPrivacyKey | und
switch (key.className) {
case 'PrivacyKeyPhoneNumber':
return 'phoneNumber';
case 'PrivacyKeyAddedByPhone':
return 'addByPhone';
case 'PrivacyKeyStatusTimestamp':
return 'lastSeen';
case 'PrivacyKeyProfilePhoto':

View File

@ -2,7 +2,7 @@ import BigInt from 'big-integer';
import { Api as GramJs } from '../../../lib/gramjs';
import { generateRandomBytes, readBigIntFromBuffer } from '../../../lib/gramjs/Helpers';
import type { ApiPrivacyKey, PrivacyVisibility } from '../../../types';
import type { ApiInputPrivacyRules, ApiPrivacyKey } from '../../../types';
import type {
ApiBotApp,
ApiChatAdminRights,
@ -25,7 +25,6 @@ import type {
ApiStorySkipped,
ApiThemeParameters,
ApiTypeReplyTo,
ApiUser,
ApiVideo,
} from '../../types';
import {
@ -458,6 +457,9 @@ export function buildInputPrivacyKey(privacyKey: ApiPrivacyKey) {
case 'phoneNumber':
return new GramJs.InputPrivacyKeyPhoneNumber();
case 'addByPhone':
return new GramJs.InputPrivacyKeyAddedByPhone();
case 'lastSeen':
return new GramJs.InputPrivacyKeyStatusTimestamp();
@ -478,6 +480,9 @@ export function buildInputPrivacyKey(privacyKey: ApiPrivacyKey) {
case 'voiceMessages':
return new GramJs.InputPrivacyKeyVoiceMessages();
case 'bio':
return new GramJs.InputPrivacyKeyAbout();
}
return undefined;
@ -660,63 +665,54 @@ export function buildInputReplyTo(replyingTo: ApiTypeReplyTo) {
}
export function buildInputPrivacyRules(
visibility: PrivacyVisibility,
allowedUserList?: ApiUser[],
deniedUserList?: ApiUser[],
rules: ApiInputPrivacyRules,
) {
const rules: GramJs.TypeInputPrivacyRule[] = [];
const privacyRules: GramJs.TypeInputPrivacyRule[] = [];
switch (visibility) {
case 'everybody':
case 'contacts': {
if (visibility === 'contacts') {
rules.push(new GramJs.InputPrivacyValueAllowContacts());
}
if (visibility === 'everybody') {
rules.push(new GramJs.InputPrivacyValueAllowAll());
}
const users = deniedUserList?.reduce<GramJs.InputUser[]>((acc, { id, accessHash }) => {
acc.push(new GramJs.InputPeerUser({
userId: buildMtpPeerId(id, 'user'),
accessHash: BigInt(accessHash!),
}));
return acc;
}, []);
if (users?.length) {
rules.push(new GramJs.InputPrivacyValueDisallowUsers({ users }));
}
break;
}
case 'closeFriends':
rules.push(new GramJs.InputPrivacyValueAllowCloseFriends());
break;
case 'nonContacts':
rules.push(new GramJs.InputPrivacyValueDisallowContacts());
break;
case 'selectedContacts': {
const users = (allowedUserList || []).reduce<GramJs.InputUser[]>((acc, { id, accessHash }) => {
acc.push(new GramJs.InputPeerUser({
userId: buildMtpPeerId(id, 'user'),
accessHash: BigInt(accessHash!),
}));
return acc;
}, []);
rules.push(new GramJs.InputPrivacyValueAllowUsers({ users }));
break;
}
case 'nobody':
rules.push(new GramJs.InputPrivacyValueDisallowAll());
break;
if (rules.allowedUsers?.length) {
privacyRules.push(new GramJs.InputPrivacyValueAllowUsers({
users: rules.allowedUsers.map(({ id, accessHash }) => buildInputEntity(id, accessHash) as GramJs.InputUser),
}));
}
if (rules.allowedChats?.length) {
privacyRules.push(new GramJs.InputPrivacyValueAllowChatParticipants({
chats: rules.allowedChats.map(({ id, type }) => (
buildMtpPeerId(id, type === 'chatTypeBasicGroup' ? 'chat' : 'channel')
)),
}));
}
if (rules.blockedUsers?.length) {
privacyRules.push(new GramJs.InputPrivacyValueDisallowUsers({
users: rules.blockedUsers.map(({ id, accessHash }) => buildInputEntity(id, accessHash) as GramJs.InputUser),
}));
}
if (rules.blockedChats?.length) {
privacyRules.push(new GramJs.InputPrivacyValueDisallowChatParticipants({
chats: rules.blockedChats.map(({ id, type }) => (
buildMtpPeerId(id, type === 'chatTypeBasicGroup' ? 'chat' : 'channel')
)),
}));
}
return rules;
if (!rules.isUnspecified) {
switch (rules.visibility) {
case 'everybody':
privacyRules.push(new GramJs.InputPrivacyValueAllowAll());
break;
case 'contacts':
privacyRules.push(new GramJs.InputPrivacyValueAllowContacts());
break;
case 'nonContacts':
privacyRules.push(new GramJs.InputPrivacyValueDisallowContacts());
break;
case 'nobody':
privacyRules.push(new GramJs.InputPrivacyValueDisallowAll());
break;
}
}
return privacyRules;
}

View File

@ -2,7 +2,7 @@ import BigInt from 'big-integer';
import { Api as GramJs } from '../../../lib/gramjs';
import type { LANG_PACKS } from '../../../config';
import type { ApiPrivacyKey, InputPrivacyRules, LangCode } from '../../../types';
import type { ApiInputPrivacyRules, ApiPrivacyKey, LangCode } from '../../../types';
import type {
ApiAppConfig,
ApiConfig,
@ -33,6 +33,7 @@ import { buildApiUser } from '../apiBuilders/users';
import {
buildInputEntity, buildInputPeer, buildInputPhoto,
buildInputPrivacyKey,
buildInputPrivacyRules,
} from '../gramjsBuilders';
import { addEntitiesToLocalDb, addPhotoToLocalDb } from '../helpers';
import localDb from '../localDb';
@ -506,48 +507,10 @@ export function unregisterDevice(token: string) {
}
export async function setPrivacySettings(
privacyKey: ApiPrivacyKey, rules: InputPrivacyRules,
privacyKey: ApiPrivacyKey, rules: ApiInputPrivacyRules,
) {
const key = buildInputPrivacyKey(privacyKey);
const privacyRules: GramJs.TypeInputPrivacyRule[] = [];
if (rules.allowedUsers) {
privacyRules.push(new GramJs.InputPrivacyValueAllowUsers({
users: rules.allowedUsers.map(({ id, accessHash }) => buildInputEntity(id, accessHash) as GramJs.InputUser),
}));
}
if (rules.allowedChats) {
privacyRules.push(new GramJs.InputPrivacyValueAllowChatParticipants({
chats: rules.allowedChats.map(({ id }) => buildInputEntity(id) as BigInt.BigInteger),
}));
}
if (rules.blockedUsers) {
privacyRules.push(new GramJs.InputPrivacyValueDisallowUsers({
users: rules.blockedUsers.map(({ id, accessHash }) => buildInputEntity(id, accessHash) as GramJs.InputUser),
}));
}
if (rules.blockedChats) {
privacyRules.push(new GramJs.InputPrivacyValueDisallowChatParticipants({
chats: rules.blockedChats.map(({ id }) => buildInputEntity(id) as BigInt.BigInteger),
}));
}
switch (rules.visibility) {
case 'everybody':
privacyRules.push(new GramJs.InputPrivacyValueAllowAll());
break;
case 'contacts':
privacyRules.push(new GramJs.InputPrivacyValueAllowContacts());
break;
case 'nonContacts':
privacyRules.push(new GramJs.InputPrivacyValueDisallowContacts());
break;
case 'nobody':
privacyRules.push(new GramJs.InputPrivacyValueDisallowAll());
break;
}
const privacyRules = buildInputPrivacyRules(rules);
const result = await invokeRequest(new GramJs.account.SetPrivacy({ key, rules: privacyRules }));

View File

@ -1,6 +1,6 @@
import { Api as GramJs } from '../../../lib/gramjs';
import type { PrivacyVisibility } from '../../../types';
import type { ApiInputPrivacyRules } from '../../../types';
import type {
ApiReaction, ApiReportReason, ApiStealthMode,
ApiTypeStory, ApiUser, ApiUserStories,
@ -306,16 +306,15 @@ export function reportStory({
}
export function editStoryPrivacy({
id, visibility, allowedUserList, deniedUserList,
id,
privacy,
}: {
id: number;
visibility: PrivacyVisibility;
allowedUserList?: ApiUser[];
deniedUserList?: ApiUser[];
privacy: ApiInputPrivacyRules;
}) {
return invokeRequest(new GramJs.stories.EditStory({
id,
privacyRules: buildInputPrivacyRules(visibility, allowedUserList, deniedUserList),
privacyRules: buildInputPrivacyRules(privacy),
}), {
shouldReturnTrue: true,
});

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M16 1.33c-8.046 0-14.667 6.006-14.667 13.552l.007.434c.116 3.6 1.671 6.751 4.393 9.131l.199.167-.097.133-.222.265-.614.685c-.395.465-.636.84-.771 1.492-.301 1.449.51 2.688 1.708 3.19 1.309.547 3.955.306 5.685-.662l.398-.231c.51-.308.945-.619 1.369-.968l.298-.253.524.069c.59.066 1.188.1 1.79.1 8.045 0 14.666-6.007 14.666-13.552C30.666 7.336 24.045 1.33 16 1.33Zm0 2.667c6.627 0 12 4.873 12 10.885s-5.373 10.885-12 10.885c-1.016 0-2.003-.115-2.945-.33-.113-.026-.235.039-.395.169l-.271.239-.349.318-.286.246-.336.265a9.433 9.433 0 0 1-1.099.716c-1.28.716-3.053.654-3.353.529-.205-.086-.151-.232.037-.462l.263-.294.219-.239.242-.275c.165-.196.338-.418.501-.669.779-1.191.457-2.609.108-2.864C5.605 21.121 4 18.31 4 14.882 4 8.87 9.372 3.997 16 3.997Z"/><path d="M11.333 14.667a2 2 0 1 1-3.999.001 2 2 0 0 1 3.999-.001ZM18 14.667a2 2 0 1 1-3.999.001A2 2 0 0 1 18 14.667ZM24.667 14.667a2 2 0 1 1-3.999.001 2 2 0 0 1 3.999-.001Z"/></svg>

After

Width:  |  Height:  |  Size: 1001 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M21.316 10.431c.224-.216.617-.391.89-.43l.017-.001h.006c.282.004.679.14.923.323l.013.01.007.007.005.005.001.001c.195.203.366.55.417.796l.002.017.001.005v.002a1.91 1.91 0 0 1-.196.875l-.016.025-.002.003-.002.002-.003.005-.098.129-7.696 8.866c-.211.206-.57.379-.824.425l-.016.003h-.015a1.83 1.83 0 0 1-.883-.239l-.029-.021-.006-.005-.002-.002-.007-.006-.127-.111-3.307-3.335c-.196-.229-.369-.62-.369-.922 0-.306.188-.71.382-.935l.011-.012.007-.007.002-.001.004-.004a1.82 1.82 0 0 1 .815-.367l.014-.001h.01c.258 0 .633.117.854.256l.004.002.004.003.016.013.009.007.121.107 2.293 2.311 6.77-7.799Z"/><path d="m28.999 8.27-.001-.02v-.021H29l-.001-.084-.002-.085v-.04l-.001-.068-.001-.069-.003-.001-.004-.001-.002-.026a3.677 3.677 0 0 0-.175-.852 3.5 3.5 0 0 0-.367-.776 3.379 3.379 0 0 0-.643-.699 3.133 3.133 0 0 0-.8-.483l-9.973-3.852A3.04 3.04 0 0 0 15.999 1a3.056 3.056 0 0 0-1.022.19L5.008 5.041a3.287 3.287 0 0 0-1.444 1.172 3.567 3.567 0 0 0-.401.876 3.611 3.611 0 0 0-.161.966c-.009.796.017 2.25.227 4.066.209 1.817.602 3.996 1.328 6.243a25.567 25.567 0 0 0 1.519 3.688 21.36 21.36 0 0 0 1.98 3.19 18.629 18.629 0 0 0 3.054 3.17 17.86 17.86 0 0 0 3.675 2.315c.185.084.387.152.593.2.207.047.418.073.621.073s.411-.025.616-.071a3.11 3.11 0 0 0 .591-.198 17.889 17.889 0 0 0 3.678-2.317 18.543 18.543 0 0 0 3.058-3.171 21.499 21.499 0 0 0 1.981-3.19 25.614 25.614 0 0 0 1.519-3.688c.696-2.155 1.086-4.246 1.302-6.015.215-1.769.257-3.216.255-4.08ZM16.144 28.098l-.034.018-.035.014h-.006l-.01.001-.023.001h-.037a.27.27 0 0 1-.059-.005.317.317 0 0 1-.067-.026c-2.461-1.137-4.317-2.775-5.725-4.644-1.408-1.869-2.367-3.969-3.033-6.028-.67-2.051-1.026-4.042-1.212-5.694a29.995 29.995 0 0 1-.196-3.658v-.004h.001c-.004-.019-.002-.04 0-.061.003-.02.004-.041.013-.059.008-.014.01-.03.022-.049.013-.019.005-.01.021-.035 0 0 .017-.022.018-.026.001-.004.016-.02.018-.025a.091.091 0 0 1 .021-.023.158.158 0 0 1 .023-.02s.075-.034.1-.043l9.958-3.85s.069-.021.076-.021c.008 0 .056.007.071.01a.276.276 0 0 1 .057.018l9.988 3.857.044-.003.006.011.007.011.005.009.005.008a.86.86 0 0 1 .034.045l.045.064a.168.168 0 0 1 .052.141v.072a29.76 29.76 0 0 1-.196 3.645c-.187 1.646-.542 3.631-1.212 5.682-.664 2.053-1.623 4.147-3.028 6.014-1.405 1.866-3.254 3.508-5.702 4.648l-.01.005Z"/></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -182,8 +182,10 @@ function LeftColumn({
return;
case SettingsScreens.PrivacyPhoneNumber:
case SettingsScreens.PrivacyAddByPhone:
case SettingsScreens.PrivacyLastSeen:
case SettingsScreens.PrivacyProfilePhoto:
case SettingsScreens.PrivacyBio:
case SettingsScreens.PrivacyPhoneCall:
case SettingsScreens.PrivacyPhoneP2P:
case SettingsScreens.PrivacyForwarding:
@ -233,6 +235,10 @@ function LeftColumn({
case SettingsScreens.PrivacyProfilePhotoDeniedContacts:
setSettingsScreen(SettingsScreens.PrivacyProfilePhoto);
return;
case SettingsScreens.PrivacyBioAllowedContacts:
case SettingsScreens.PrivacyBioDeniedContacts:
setSettingsScreen(SettingsScreens.PrivacyBio);
return;
case SettingsScreens.PrivacyPhoneCallAllowedContacts:
case SettingsScreens.PrivacyPhoneCallDeniedContacts:
setSettingsScreen(SettingsScreens.PrivacyPhoneCall);

View File

@ -106,8 +106,15 @@
}
.settings-main-menu {
padding: 0 0.5rem 0.75rem;
padding: 0.5rem;
background-color: var(--color-background);
box-shadow: inset 0 -0.0625rem 0 0 var(--color-background-secondary-accent);
border-bottom: 0.625rem solid var(--color-background-secondary);
&:last-child {
border-bottom: none;
box-shadow: none;
}
> .ChatExtra {
padding: 0 0.5rem 0.3125rem;

View File

@ -99,6 +99,11 @@ const PRIVACY_PROFILE_PHOTO_SCREENS = [
SettingsScreens.PrivacyProfilePhotoDeniedContacts,
];
const PRIVACY_BIO_SCREENS = [
SettingsScreens.PrivacyBioAllowedContacts,
SettingsScreens.PrivacyBioDeniedContacts,
];
const PRIVACY_PHONE_CALL_SCREENS = [
SettingsScreens.PrivacyPhoneCallAllowedContacts,
SettingsScreens.PrivacyPhoneCallDeniedContacts,
@ -190,6 +195,7 @@ const Settings: FC<OwnProps> = ({
[SettingsScreens.PrivacyPhoneNumber]: PRIVACY_PHONE_NUMBER_SCREENS.includes(screen),
[SettingsScreens.PrivacyLastSeen]: PRIVACY_LAST_SEEN_PHONE_SCREENS.includes(screen),
[SettingsScreens.PrivacyProfilePhoto]: PRIVACY_PROFILE_PHOTO_SCREENS.includes(screen),
[SettingsScreens.PrivacyBio]: PRIVACY_BIO_SCREENS.includes(screen),
[SettingsScreens.PrivacyPhoneCall]: PRIVACY_PHONE_CALL_SCREENS.includes(screen),
[SettingsScreens.PrivacyPhoneP2P]: PRIVACY_PHONE_P2P_SCREENS.includes(screen),
[SettingsScreens.PrivacyForwarding]: PRIVACY_FORWARDING_SCREENS.includes(screen),
@ -314,8 +320,8 @@ const Settings: FC<OwnProps> = ({
case SettingsScreens.PrivacyPhoneNumber:
case SettingsScreens.PrivacyLastSeen:
case SettingsScreens.PrivacyProfilePhoto:
case SettingsScreens.PrivacyBio:
case SettingsScreens.PrivacyPhoneCall:
case SettingsScreens.PrivacyPhoneP2P:
case SettingsScreens.PrivacyForwarding:
case SettingsScreens.PrivacyVoiceMessages:
case SettingsScreens.PrivacyGroupChats:
@ -331,6 +337,7 @@ const Settings: FC<OwnProps> = ({
case SettingsScreens.PrivacyPhoneNumberAllowedContacts:
case SettingsScreens.PrivacyLastSeenAllowedContacts:
case SettingsScreens.PrivacyProfilePhotoAllowedContacts:
case SettingsScreens.PrivacyBioAllowedContacts:
case SettingsScreens.PrivacyPhoneCallAllowedContacts:
case SettingsScreens.PrivacyPhoneP2PAllowedContacts:
case SettingsScreens.PrivacyForwardingAllowedContacts:
@ -349,6 +356,7 @@ const Settings: FC<OwnProps> = ({
case SettingsScreens.PrivacyPhoneNumberDeniedContacts:
case SettingsScreens.PrivacyLastSeenDeniedContacts:
case SettingsScreens.PrivacyProfilePhotoDeniedContacts:
case SettingsScreens.PrivacyBioDeniedContacts:
case SettingsScreens.PrivacyPhoneCallDeniedContacts:
case SettingsScreens.PrivacyPhoneP2PDeniedContacts:
case SettingsScreens.PrivacyForwardingDeniedContacts:

View File

@ -113,20 +113,21 @@ const SettingsHeader: FC<OwnProps> = ({
return <h3>{lang('PrivacyLastSeen')}</h3>;
case SettingsScreens.PrivacyProfilePhoto:
return <h3>{lang('Privacy.ProfilePhoto')}</h3>;
case SettingsScreens.PrivacyBio:
return <h3>{lang('PrivacyBio')}</h3>;
case SettingsScreens.PrivacyForwarding:
return <h3>{lang('PrivacyForwards')}</h3>;
case SettingsScreens.PrivacyVoiceMessages:
return <h3>{lang('PrivacyVoiceMessages')}</h3>;
case SettingsScreens.PrivacyGroupChats:
return <h3>{lang('AutodownloadGroupChats')}</h3>;
case SettingsScreens.PrivacyPhoneP2P:
return <h3>{lang('PrivacyP2P')}</h3>;
case SettingsScreens.PrivacyPhoneCall:
return <h3>{lang('Calls')}</h3>;
case SettingsScreens.PrivacyPhoneNumberAllowedContacts:
case SettingsScreens.PrivacyLastSeenAllowedContacts:
case SettingsScreens.PrivacyProfilePhotoAllowedContacts:
case SettingsScreens.PrivacyBioAllowedContacts:
case SettingsScreens.PrivacyForwardingAllowedContacts:
case SettingsScreens.PrivacyVoiceMessagesAllowedContacts:
case SettingsScreens.PrivacyGroupChatsAllowedContacts:
@ -136,6 +137,7 @@ const SettingsHeader: FC<OwnProps> = ({
case SettingsScreens.PrivacyPhoneNumberDeniedContacts:
case SettingsScreens.PrivacyLastSeenDeniedContacts:
case SettingsScreens.PrivacyProfilePhotoDeniedContacts:
case SettingsScreens.PrivacyBioDeniedContacts:
case SettingsScreens.PrivacyForwardingDeniedContacts:
case SettingsScreens.PrivacyVoiceMessagesDeniedContacts:
case SettingsScreens.PrivacyGroupChatsDeniedContacts:

View File

@ -4,14 +4,18 @@ import { getActions, withGlobal } from '../../../global';
import { SettingsScreens } from '../../../types';
import { FAQ_URL, PRIVACY_URL } from '../../../config';
import { selectIsPremiumPurchaseBlocked } from '../../../global/selectors';
import useFlag from '../../../hooks/useFlag';
import useHistoryBack from '../../../hooks/useHistoryBack';
import useLang from '../../../hooks/useLang';
import useLastCallback from '../../../hooks/useLastCallback';
import ChatExtra from '../../common/ChatExtra';
import PremiumIcon from '../../common/PremiumIcon';
import ProfileInfo from '../../common/ProfileInfo';
import ConfirmDialog from '../../ui/ConfirmDialog';
import ListItem from '../../ui/ListItem';
type OwnProps = {
@ -38,8 +42,12 @@ const SettingsMain: FC<OwnProps & StateProps> = ({
loadProfilePhotos,
loadAuthorizations,
openPremiumModal,
openSupportChat,
openUrl,
} = getActions();
const [isSupportDialogOpen, openSupportDialog, closeSupportDialog] = useFlag(false);
const lang = useLang();
useEffect(() => {
@ -57,6 +65,11 @@ const SettingsMain: FC<OwnProps & StateProps> = ({
loadAuthorizations();
}, []);
const handleOpenSupport = useLastCallback(() => {
openSupportChat();
closeSupportDialog();
});
return (
<div className="settings-content custom-scroll">
<div className="settings-main-menu">
@ -138,6 +151,8 @@ const SettingsMain: FC<OwnProps & StateProps> = ({
>
{lang('StickersName')}
</ListItem>
</div>
<div className="settings-main-menu">
{canBuyPremium && (
<ListItem
leftElement={<PremiumIcon withGradient big />}
@ -149,6 +164,36 @@ const SettingsMain: FC<OwnProps & StateProps> = ({
</ListItem>
)}
</div>
<div className="settings-main-menu">
<ListItem
icon="ask-support"
onClick={openSupportDialog}
>
{lang('AskAQuestion')}
</ListItem>
<ListItem
icon="help"
// eslint-disable-next-line react/jsx-no-bind
onClick={() => openUrl({ url: FAQ_URL })}
>
{lang('TelegramFaq')}
</ListItem>
<ListItem
icon="privacy-policy"
// eslint-disable-next-line react/jsx-no-bind
onClick={() => openUrl({ url: PRIVACY_URL })}
>
{lang('PrivacyPolicy')}
</ListItem>
</div>
<ConfirmDialog
isOpen={isSupportDialogOpen}
confirmLabel={lang('lng_settings_ask_ok')}
title={lang('AskAQuestion')}
text={lang('lng_settings_ask_sure')}
confirmHandler={handleOpenSupport}
onClose={closeSupportDialog}
/>
</div>
);
};

View File

@ -38,7 +38,7 @@ type StateProps = {
privacyVoiceMessages?: ApiPrivacySettings;
privacyGroupChats?: ApiPrivacySettings;
privacyPhoneCall?: ApiPrivacySettings;
privacyPhoneP2P?: ApiPrivacySettings;
privacyBio?: ApiPrivacySettings;
};
const SettingsPrivacy: FC<OwnProps & StateProps> = ({
@ -53,6 +53,7 @@ const SettingsPrivacy: FC<OwnProps & StateProps> = ({
canDisplayAutoarchiveSetting,
shouldArchiveAndMuteNewNonContact,
canDisplayChatInTitle,
canSetPasscode,
privacyPhoneNumber,
privacyLastSeen,
privacyProfilePhoto,
@ -60,10 +61,9 @@ const SettingsPrivacy: FC<OwnProps & StateProps> = ({
privacyVoiceMessages,
privacyGroupChats,
privacyPhoneCall,
privacyPhoneP2P,
privacyBio,
onScreenSelect,
onReset,
canSetPasscode,
}) => {
const {
loadPrivacySettings,
@ -250,25 +250,12 @@ const SettingsPrivacy: FC<OwnProps & StateProps> = ({
narrow
className="no-icon"
// eslint-disable-next-line react/jsx-no-bind
onClick={() => onScreenSelect(SettingsScreens.PrivacyPhoneCall)}
onClick={() => onScreenSelect(SettingsScreens.PrivacyBio)}
>
<div className="multiline-menu-item">
<span className="title">{lang('WhoCanCallMe')}</span>
<span className="title">{lang('PrivacyBio')}</span>
<span className="subtitle" dir="auto">
{getVisibilityValue(privacyPhoneCall)}
</span>
</div>
</ListItem>
<ListItem
narrow
className="no-icon"
// eslint-disable-next-line react/jsx-no-bind
onClick={() => onScreenSelect(SettingsScreens.PrivacyPhoneP2P)}
>
<div className="multiline-menu-item">
<span className="title">{lang('PrivacyP2P')}</span>
<span className="subtitle" dir="auto">
{getVisibilityValue(privacyPhoneP2P)}
{getVisibilityValue(privacyBio)}
</span>
</div>
</ListItem>
@ -287,16 +274,14 @@ const SettingsPrivacy: FC<OwnProps & StateProps> = ({
</ListItem>
<ListItem
narrow
disabled={!isCurrentUserPremium}
allowDisabledClick
rightElement={!isCurrentUserPremium && <i className="icon icon-lock-badge settings-icon-locked" />}
className="no-icon"
onClick={handleVoiceMessagesClick}
// eslint-disable-next-line react/jsx-no-bind
onClick={() => onScreenSelect(SettingsScreens.PrivacyPhoneCall)}
>
<div className="multiline-menu-item">
<span className="title">{lang('PrivacyVoiceMessagesTitle')}</span>
<span className="title">{lang('WhoCanCallMe')}</span>
<span className="subtitle" dir="auto">
{getVisibilityValue(privacyVoiceMessages)}
{getVisibilityValue(privacyPhoneCall)}
</span>
</div>
</ListItem>
@ -313,6 +298,21 @@ const SettingsPrivacy: FC<OwnProps & StateProps> = ({
</span>
</div>
</ListItem>
<ListItem
narrow
disabled={!isCurrentUserPremium}
allowDisabledClick
rightElement={!isCurrentUserPremium && <i className="icon icon-lock-badge settings-icon-locked" />}
className="no-icon"
onClick={handleVoiceMessagesClick}
>
<div className="multiline-menu-item">
<span className="title">{lang('PrivacyVoiceMessagesTitle')}</span>
<span className="subtitle" dir="auto">
{getVisibilityValue(privacyVoiceMessages)}
</span>
</div>
</ListItem>
</div>
{canDisplayAutoarchiveSetting && (
@ -392,7 +392,7 @@ export default memo(withGlobal<OwnProps>(
privacyVoiceMessages: privacy.voiceMessages,
privacyGroupChats: privacy.chatInvite,
privacyPhoneCall: privacy.phoneCall,
privacyPhoneP2P: privacy.phoneP2P,
privacyBio: privacy.bio,
canDisplayChatInTitle,
canSetPasscode: selectCanSetPasscode(global),
};

View File

@ -2,7 +2,7 @@ import type { FC } from '../../../lib/teact/teact';
import React, { memo, useCallback, useMemo } from '../../../lib/teact/teact';
import { getActions, withGlobal } from '../../../global';
import type { ApiChat, ApiPhoto, ApiUser } from '../../../api/types';
import type { ApiPhoto } from '../../../api/types';
import type { ApiPrivacySettings } from '../../../types';
import { SettingsScreens } from '../../../types';
@ -11,6 +11,7 @@ import { getPrivacyKey } from './helpers/privacy';
import useHistoryBack from '../../../hooks/useHistoryBack';
import useLang from '../../../hooks/useLang';
import useLastCallback from '../../../hooks/useLastCallback';
import ListItem from '../../ui/ListItem';
import RadioGroup from '../../ui/RadioGroup';
@ -23,57 +24,131 @@ type OwnProps = {
onReset: () => void;
};
type StateProps =
Partial<ApiPrivacySettings> & {
chatsById?: Record<string, ApiChat>;
usersById?: Record<string, ApiUser>;
currentUserId: string;
hasCurrentUserFullInfo?: boolean;
currentUserFallbackPhoto?: ApiPhoto;
};
type StateProps = {
currentUserId: string;
hasCurrentUserFullInfo?: boolean;
currentUserFallbackPhoto?: ApiPhoto;
primaryPrivacy?: ApiPrivacySettings;
secondaryPrivacy?: ApiPrivacySettings;
};
const SettingsPrivacyVisibility: FC<OwnProps & StateProps> = ({
screen,
isActive,
onScreenSelect,
onReset,
visibility,
allowUserIds,
allowChatIds,
blockUserIds,
blockChatIds,
chatsById,
primaryPrivacy,
secondaryPrivacy,
currentUserId,
hasCurrentUserFullInfo,
currentUserFallbackPhoto,
onScreenSelect,
onReset,
}) => {
const { setPrivacyVisibility } = getActions();
useHistoryBack({
isActive,
onBack: onReset,
});
const secondaryScreen = useMemo(() => {
switch (screen) {
case SettingsScreens.PrivacyPhoneCall:
return SettingsScreens.PrivacyPhoneP2P;
case SettingsScreens.PrivacyPhoneNumber: {
return primaryPrivacy?.visibility === 'nobody' ? SettingsScreens.PrivacyAddByPhone : undefined;
}
default:
return undefined;
}
}, [primaryPrivacy, screen]);
return (
<div className="settings-content custom-scroll">
<PrivacySubsection
screen={screen}
privacy={primaryPrivacy}
onScreenSelect={onScreenSelect}
/>
{screen === SettingsScreens.PrivacyProfilePhoto && primaryPrivacy?.visibility !== 'everybody' && (
<SettingsPrivacyPublicProfilePhoto
currentUserId={currentUserId}
hasCurrentUserFullInfo={hasCurrentUserFullInfo}
currentUserFallbackPhoto={currentUserFallbackPhoto}
/>
)}
{secondaryScreen && (
<PrivacySubsection
screen={secondaryScreen}
privacy={secondaryPrivacy}
onScreenSelect={onScreenSelect}
/>
)}
</div>
);
};
function PrivacySubsection({
screen,
privacy,
onScreenSelect,
}: {
screen: SettingsScreens;
privacy?: ApiPrivacySettings;
onScreenSelect: (screen: SettingsScreens) => void;
}) {
const { setPrivacyVisibility } = getActions();
const lang = useLang();
const visibilityOptions = useMemo(() => {
return [
const hasNobody = screen !== SettingsScreens.PrivacyAddByPhone;
const options = [
{ value: 'everybody', label: lang('P2PEverybody') },
{ value: 'contacts', label: lang('P2PContacts') },
{ value: 'nobody', label: lang('P2PNobody') },
];
}, [lang]);
if (hasNobody) {
options.push({ value: 'nobody', label: lang('P2PNobody') });
}
return options;
}, [lang, screen]);
const exceptionLists = {
shouldShowDenied: visibility !== 'nobody',
shouldShowAllowed: visibility !== 'everybody',
};
const primaryExceptionLists = useMemo(() => {
if (screen === SettingsScreens.PrivacyAddByPhone) {
return {
shouldShowDenied: false,
shouldShowAllowed: false,
};
}
return {
shouldShowDenied: privacy?.visibility !== 'nobody',
shouldShowAllowed: privacy?.visibility !== 'everybody',
};
}, [privacy, screen]);
const privacyKey = getPrivacyKey(screen);
const descriptionText = useMemo(() => {
switch (screen) {
case SettingsScreens.PrivacyLastSeen:
return lang('CustomHelp');
case SettingsScreens.PrivacyAddByPhone: {
return privacy?.visibility === 'everybody' ? lang('PrivacyPhoneInfo') : lang('PrivacyPhoneInfo3');
}
default:
return undefined;
}
}, [lang, screen, privacy]);
const headerText = useMemo(() => {
switch (screen) {
case SettingsScreens.PrivacyPhoneNumber:
return lang('PrivacyPhoneTitle');
case SettingsScreens.PrivacyAddByPhone:
return lang('PrivacyPhoneTitle2');
case SettingsScreens.PrivacyLastSeen:
return lang('LastSeenTitle');
case SettingsScreens.PrivacyProfilePhoto:
return lang('PrivacyProfilePhotoTitle');
case SettingsScreens.PrivacyBio:
return lang('PrivacyBioTitle');
case SettingsScreens.PrivacyForwarding:
return lang('PrivacyForwardsTitle');
case SettingsScreens.PrivacyVoiceMessages:
@ -89,19 +164,34 @@ const SettingsPrivacyVisibility: FC<OwnProps & StateProps> = ({
}
}, [lang, screen]);
useHistoryBack({
isActive,
onBack: onReset,
const prepareSubtitle = useLastCallback((userIds?: string[], chatIds?: string[]) => {
const userIdsCount = userIds?.length || 0;
const chatIdsCount = chatIds?.length || 0;
if (!userIdsCount && !chatIdsCount) {
return lang('EditAdminAddUsers');
}
const userCountString = userIdsCount > 0 ? lang('Users', userIdsCount) : undefined;
const chatCountString = chatIdsCount > 0 ? lang('Chats', chatIdsCount) : undefined;
return [userCountString, chatCountString].filter(Boolean).join(', ');
});
const descriptionText = useMemo(() => {
switch (screen) {
case SettingsScreens.PrivacyLastSeen:
return lang('CustomHelp');
default:
return undefined;
}
}, [lang, screen]);
const allowedString = useMemo(() => {
return prepareSubtitle(privacy?.allowUserIds, privacy?.allowChatIds);
}, [privacy]);
const blockString = useMemo(() => {
return prepareSubtitle(privacy?.blockUserIds, privacy?.blockChatIds);
}, [privacy]);
const handleVisibilityChange = useCallback((value) => {
setPrivacyVisibility({
privacyKey: privacyKey!,
visibility: value,
});
}, [privacyKey]);
const allowedContactsScreen = (() => {
switch (screen) {
@ -111,6 +201,8 @@ const SettingsPrivacyVisibility: FC<OwnProps & StateProps> = ({
return SettingsScreens.PrivacyLastSeenAllowedContacts;
case SettingsScreens.PrivacyProfilePhoto:
return SettingsScreens.PrivacyProfilePhotoAllowedContacts;
case SettingsScreens.PrivacyBio:
return SettingsScreens.PrivacyBioAllowedContacts;
case SettingsScreens.PrivacyForwarding:
return SettingsScreens.PrivacyForwardingAllowedContacts;
case SettingsScreens.PrivacyPhoneCall:
@ -132,6 +224,8 @@ const SettingsPrivacyVisibility: FC<OwnProps & StateProps> = ({
return SettingsScreens.PrivacyLastSeenDeniedContacts;
case SettingsScreens.PrivacyProfilePhoto:
return SettingsScreens.PrivacyProfilePhotoDeniedContacts;
case SettingsScreens.PrivacyBio:
return SettingsScreens.PrivacyBioDeniedContacts;
case SettingsScreens.PrivacyForwarding:
return SettingsScreens.PrivacyForwardingDeniedContacts;
case SettingsScreens.PrivacyPhoneCall:
@ -145,105 +239,68 @@ const SettingsPrivacyVisibility: FC<OwnProps & StateProps> = ({
}
})();
const allowedCount = useMemo(() => {
if (!allowUserIds || !allowChatIds || !chatsById) {
return 0;
}
return allowChatIds.reduce((result, chatId) => {
return result + (chatsById[chatId] ? chatsById[chatId].membersCount! : 0);
}, allowUserIds.length);
}, [allowChatIds, allowUserIds, chatsById]);
const blockCount = useMemo(() => {
if (!blockUserIds || !blockChatIds || !chatsById) {
return 0;
}
return blockChatIds.reduce((result, chatId) => {
return result + (chatsById[chatId] ? chatsById[chatId].membersCount! : 0);
}, blockUserIds.length);
}, [blockChatIds, blockUserIds, chatsById]);
const handleVisibilityChange = useCallback((value) => {
setPrivacyVisibility({
privacyKey: privacyKey!,
visibility: value,
});
}, [privacyKey, setPrivacyVisibility]);
return (
<div className="settings-content custom-scroll">
<>
<div className="settings-item">
<h4 className="settings-item-header" dir={lang.isRtl ? 'rtl' : undefined}>{headerText}</h4>
<RadioGroup
name={`visibility-${privacyKey}`}
options={visibilityOptions}
onChange={handleVisibilityChange}
selected={visibility}
selected={privacy?.visibility}
/>
{descriptionText && (
<p className="settings-item-description-larger" dir={lang.isRtl ? 'rtl' : undefined}>{descriptionText}</p>
)}
</div>
<div className="settings-item">
<h4 className="settings-item-header mb-4" dir={lang.isRtl ? 'rtl' : undefined}>{lang('PrivacyExceptions')}</h4>
{exceptionLists.shouldShowAllowed && (
<ListItem
narrow
icon="add-user"
// eslint-disable-next-line react/jsx-no-bind
onClick={() => {
onScreenSelect(allowedContactsScreen);
}}
>
<div className="multiline-menu-item full-size">
{allowedCount > 0 && <span className="date" dir="auto">+{allowedCount}</span>}
<span className="title">{lang('AlwaysAllow')}</span>
<span className="subtitle">{lang('EditAdminAddUsers')}</span>
</div>
</ListItem>
)}
{exceptionLists.shouldShowDenied && (
<ListItem
narrow
icon="delete-user"
// eslint-disable-next-line react/jsx-no-bind
onClick={() => {
onScreenSelect(deniedContactsScreen);
}}
>
<div className="multiline-menu-item full-size">
{blockCount > 0 && <span className="date" dir="auto">&minus;{blockCount}</span>}
<span className="title">{lang('NeverAllow')}</span>
<span className="subtitle">{lang('EditAdminAddUsers')}</span>
</div>
</ListItem>
)}
</div>
{screen === SettingsScreens.PrivacyProfilePhoto && exceptionLists.shouldShowAllowed && (
<SettingsPrivacyPublicProfilePhoto
currentUserId={currentUserId}
hasCurrentUserFullInfo={hasCurrentUserFullInfo}
currentUserFallbackPhoto={currentUserFallbackPhoto}
/>
{(primaryExceptionLists.shouldShowAllowed || primaryExceptionLists.shouldShowDenied) && (
<div className="settings-item">
<h4 className="settings-item-header mb-4" dir={lang.isRtl ? 'rtl' : undefined}>
{lang('PrivacyExceptions')}
</h4>
{primaryExceptionLists.shouldShowAllowed && (
<ListItem
narrow
icon="add-user"
// eslint-disable-next-line react/jsx-no-bind
onClick={() => {
onScreenSelect(allowedContactsScreen);
}}
>
<div className="multiline-menu-item full-size">
<span className="title">{lang('AlwaysAllow')}</span>
<span className="subtitle">{allowedString}</span>
</div>
</ListItem>
)}
{primaryExceptionLists.shouldShowDenied && (
<ListItem
narrow
icon="delete-user"
// eslint-disable-next-line react/jsx-no-bind
onClick={() => {
onScreenSelect(deniedContactsScreen);
}}
>
<div className="multiline-menu-item full-size">
<span className="title">{lang('NeverAllow')}</span>
<span className="subtitle">{blockString}</span>
</div>
</ListItem>
)}
</div>
)}
</div>
</>
);
};
}
export default memo(withGlobal<OwnProps>(
(global, { screen }): StateProps => {
let privacySettings: ApiPrivacySettings | undefined;
let primaryPrivacy: ApiPrivacySettings | undefined;
let secondaryPrivacy: ApiPrivacySettings | undefined;
const {
currentUserId,
chats: { byId: chatsById },
settings: { privacy },
} = global;
@ -251,39 +308,42 @@ export default memo(withGlobal<OwnProps>(
switch (screen) {
case SettingsScreens.PrivacyPhoneNumber:
privacySettings = privacy.phoneNumber;
primaryPrivacy = privacy.phoneNumber;
secondaryPrivacy = privacy.addByPhone;
break;
case SettingsScreens.PrivacyLastSeen:
privacySettings = privacy.lastSeen;
primaryPrivacy = privacy.lastSeen;
break;
case SettingsScreens.PrivacyProfilePhoto:
privacySettings = privacy.profilePhoto;
primaryPrivacy = privacy.profilePhoto;
break;
case SettingsScreens.PrivacyPhoneCall:
privacySettings = privacy.phoneCall;
case SettingsScreens.PrivacyBio:
primaryPrivacy = privacy.bio;
break;
case SettingsScreens.PrivacyPhoneP2P:
privacySettings = privacy.phoneP2P;
case SettingsScreens.PrivacyPhoneCall:
primaryPrivacy = privacy.phoneCall;
secondaryPrivacy = privacy.phoneP2P;
break;
case SettingsScreens.PrivacyForwarding:
privacySettings = privacy.forwards;
primaryPrivacy = privacy.forwards;
break;
case SettingsScreens.PrivacyVoiceMessages:
privacySettings = privacy.voiceMessages;
primaryPrivacy = privacy.voiceMessages;
break;
case SettingsScreens.PrivacyGroupChats:
privacySettings = privacy.chatInvite;
primaryPrivacy = privacy.chatInvite;
break;
}
if (!privacySettings) {
if (!primaryPrivacy) {
return {
currentUserId: currentUserId!,
hasCurrentUserFullInfo: Boolean(currentUserFullInfo),
@ -292,8 +352,8 @@ export default memo(withGlobal<OwnProps>(
}
return {
...privacySettings,
chatsById,
primaryPrivacy,
secondaryPrivacy,
currentUserId: currentUserId!,
hasCurrentUserFullInfo: Boolean(currentUserFullInfo),
currentUserFallbackPhoto: currentUserFullInfo?.fallbackPhoto,

View File

@ -1,6 +1,6 @@
import type { FC } from '../../../lib/teact/teact';
import React, {
memo, useCallback, useMemo, useState,
memo, useCallback, useEffect, useMemo, useState,
} from '../../../lib/teact/teact';
import { getActions, getGlobal, withGlobal } from '../../../global';
@ -9,7 +9,7 @@ import type { ApiPrivacySettings } from '../../../types';
import { SettingsScreens } from '../../../types';
import { ALL_FOLDER_ID, ARCHIVED_FOLDER_ID } from '../../../config';
import { filterChatsByName, isUserId } from '../../../global/helpers';
import { filterChatsByName } from '../../../global/helpers';
import { unique } from '../../../util/iteratees';
import { getPrivacyKey } from './helpers/privacy';
@ -37,10 +37,10 @@ const SettingsPrivacyVisibilityExceptionList: FC<OwnProps & StateProps> = ({
isAllowList,
screen,
isActive,
onScreenSelect,
onReset,
currentUserId,
settings,
onScreenSelect,
onReset,
}) => {
const { setPrivacySettings } = getActions();
@ -61,6 +61,11 @@ const SettingsPrivacyVisibilityExceptionList: FC<OwnProps & StateProps> = ({
const [isSubmitShown, setIsSubmitShown] = useState<boolean>(false);
const [newSelectedContactIds, setNewSelectedContactIds] = useState<string[]>(selectedContactIds);
// Reset selected contact ids on change from other client when screen is not active
useEffect(() => {
if (!isActive) setNewSelectedContactIds(selectedContactIds);
}, [isActive, selectedContactIds]);
const folderAllOrderedIds = useFolderManagerForOrderedIds(ALL_FOLDER_ID);
const folderArchivedOrderedIds = useFolderManagerForOrderedIds(ARCHIVED_FOLDER_ID);
const displayedIds = useMemo(() => {
@ -68,11 +73,7 @@ const SettingsPrivacyVisibilityExceptionList: FC<OwnProps & StateProps> = ({
const chatsById = getGlobal().chats.byId;
const chatIds = unique([...folderAllOrderedIds || [], ...folderArchivedOrderedIds || []])
.filter((chatId) => {
const chat = chatsById[chatId];
return chat && isUserId(chat.id) && chat.id !== currentUserId;
});
.filter((chatId) => chatId !== currentUserId);
return unique([
...selectedContactIds,
@ -89,7 +90,7 @@ const SettingsPrivacyVisibilityExceptionList: FC<OwnProps & StateProps> = ({
setPrivacySettings({
privacyKey: getPrivacyKey(screen)!,
isAllowList: Boolean(isAllowList),
contactsIds: newSelectedContactIds,
updatedIds: newSelectedContactIds,
});
onScreenSelect(SettingsScreens.Privacy);
@ -136,6 +137,9 @@ function getCurrentPrivacySettings(global: GlobalState, screen: SettingsScreens)
case SettingsScreens.PrivacyProfilePhotoAllowedContacts:
case SettingsScreens.PrivacyProfilePhotoDeniedContacts:
return privacy.profilePhoto;
case SettingsScreens.PrivacyBioAllowedContacts:
case SettingsScreens.PrivacyBioDeniedContacts:
return privacy.bio;
case SettingsScreens.PrivacyPhoneCallAllowedContacts:
case SettingsScreens.PrivacyPhoneCallDeniedContacts:
return privacy.phoneCall;

View File

@ -15,6 +15,10 @@ export function getPrivacyKey(screen: SettingsScreens): ApiPrivacyKey | undefine
case SettingsScreens.PrivacyProfilePhotoAllowedContacts:
case SettingsScreens.PrivacyProfilePhotoDeniedContacts:
return 'profilePhoto';
case SettingsScreens.PrivacyBio:
case SettingsScreens.PrivacyBioAllowedContacts:
case SettingsScreens.PrivacyBioDeniedContacts:
return 'bio';
case SettingsScreens.PrivacyForwarding:
case SettingsScreens.PrivacyForwardingAllowedContacts:
case SettingsScreens.PrivacyForwardingDeniedContacts:
@ -35,6 +39,8 @@ export function getPrivacyKey(screen: SettingsScreens): ApiPrivacyKey | undefine
case SettingsScreens.PrivacyPhoneP2PAllowedContacts:
case SettingsScreens.PrivacyPhoneP2PDeniedContacts:
return 'phoneP2P';
case SettingsScreens.PrivacyAddByPhone:
return 'addByPhone';
}
return undefined;

View File

@ -439,12 +439,12 @@ function Story({
const handleInfoPrivacyClick = useLastCallback(() => {
const visibility = !isLoadedStory || story.isPublic
? undefined
: story.isForContacts ? 'contacts' : (story.isForCloseFriends ? 'closeFriends' : 'selectedContacts');
: story.isForContacts ? 'contacts' : (story.isForCloseFriends ? 'closeFriends' : 'nobody');
let message;
const myName = getUserFirstOrLastName(user);
switch (visibility) {
case 'selectedContacts':
case 'nobody':
message = lang('StorySelectedContactsHint', myName);
break;
case 'contacts':
@ -560,7 +560,7 @@ function Story({
case 'closeFriends':
privacyIcon = 'favorite-filled';
break;
case 'selectedContacts':
case 'nobody':
privacyIcon = 'group-filled';
}
} else {

View File

@ -69,7 +69,7 @@ const OPTIONS: PrivacyOption[] = [{
actions: 'closeFriends',
}, {
name: 'StoryPrivacyOptionSelectedContacts',
value: 'selectedContacts',
value: 'nobody',
color: ['#FFB743', '#F69A36'],
icon: 'group-filled',
actions: 'allowUserIds',

View File

@ -293,6 +293,8 @@ export const DEFAULT_LANG_CODE = 'en';
export const DEFAULT_LANG_PACK = 'android';
export const LANG_PACKS = ['android', 'ios', 'tdesktop', 'macos'] as const;
export const FEEDBACK_URL = 'https://bugs.telegram.org/?tag_ids=41&sort=time';
export const FAQ_URL = 'https://telegram.org/faq';
export const PRIVACY_URL = 'https://telegram.org/privacy';
export const MINI_APP_TOS_URL = 'https://telegram.org/tos/mini-apps';
export const GENERAL_TOPIC_ID = 1;
export const STORY_EXPIRE_PERIOD = 86400; // 1 day

View File

@ -1,9 +1,8 @@
import type { ApiUser, ApiUsername } from '../../../api/types';
import type {
ApiPrivacySettings,
InputPrivacyContact, InputPrivacyRules, PrivacyVisibility,
} from '../../../types';
import type { ActionReturnType, GlobalState } from '../../types';
import type { ActionReturnType } from '../../types';
import {
ProfileEditProgress,
UPLOADING_WALLPAPER_SLUG,
@ -17,7 +16,7 @@ import { requestPermission, subscribe, unsubscribe } from '../../../util/notific
import requestActionTimeout from '../../../util/requestActionTimeout';
import { getServerTime } from '../../../util/serverTime';
import { callApi } from '../../../api/gramjs';
import { isUserId } from '../../helpers';
import { buildApiInputPrivacyRules } from '../../helpers';
import { addActionHandler, getGlobal, setGlobal } from '../../index';
import {
addBlockedUser, addNotifyExceptions, addUsers, removeBlockedUser, replaceSettings, updateChat, updateChats,
@ -413,6 +412,7 @@ addActionHandler('loadLanguages', async (global): Promise<void> => {
addActionHandler('loadPrivacySettings', async (global): Promise<void> => {
const result = await Promise.all([
callApi('fetchPrivacySettings', 'phoneNumber'),
callApi('fetchPrivacySettings', 'addByPhone'),
callApi('fetchPrivacySettings', 'lastSeen'),
callApi('fetchPrivacySettings', 'profilePhoto'),
callApi('fetchPrivacySettings', 'forwards'),
@ -420,6 +420,7 @@ addActionHandler('loadPrivacySettings', async (global): Promise<void> => {
callApi('fetchPrivacySettings', 'phoneCall'),
callApi('fetchPrivacySettings', 'phoneP2P'),
callApi('fetchPrivacySettings', 'voiceMessages'),
callApi('fetchPrivacySettings', 'bio'),
]);
if (result.some((e) => e === undefined)) {
@ -428,6 +429,7 @@ addActionHandler('loadPrivacySettings', async (global): Promise<void> => {
const [
phoneNumberSettings,
addByPhoneSettings,
lastSeenSettings,
profilePhotoSettings,
forwardsSettings,
@ -435,6 +437,7 @@ addActionHandler('loadPrivacySettings', async (global): Promise<void> => {
phoneCallSettings,
phoneP2PSettings,
voiceMessagesSettings,
bioSettings,
] = result as {
users: ApiUser[];
rules: ApiPrivacySettings;
@ -451,6 +454,7 @@ addActionHandler('loadPrivacySettings', async (global): Promise<void> => {
privacy: {
...global.settings.privacy,
phoneNumber: phoneNumberSettings.rules,
addByPhone: addByPhoneSettings.rules,
lastSeen: lastSeenSettings.rules,
profilePhoto: profilePhotoSettings.rules,
forwards: forwardsSettings.rules,
@ -458,6 +462,7 @@ addActionHandler('loadPrivacySettings', async (global): Promise<void> => {
phoneCall: phoneCallSettings.rules,
phoneP2P: phoneP2PSettings.rules,
voiceMessages: voiceMessagesSettings.rules,
bio: bioSettings.rules,
},
},
};
@ -475,10 +480,10 @@ addActionHandler('setPrivacyVisibility', async (global, actions, payload): Promi
return;
}
const rules = buildInputPrivacyRules(global, {
const rules = buildApiInputPrivacyRules(global, {
visibility,
allowedIds: [...settings.allowUserIds, ...settings.allowChatIds],
deniedIds: [...settings.blockUserIds, ...settings.blockChatIds],
blockedIds: [...settings.blockUserIds, ...settings.blockChatIds],
});
const result = await callApi('setPrivacySettings', privacyKey, rules);
@ -502,7 +507,7 @@ addActionHandler('setPrivacyVisibility', async (global, actions, payload): Promi
});
addActionHandler('setPrivacySettings', async (global, actions, payload): Promise<void> => {
const { privacyKey, isAllowList, contactsIds } = payload!;
const { privacyKey, isAllowList, updatedIds } = payload!;
const {
privacy: { [privacyKey]: settings },
} = global.settings;
@ -511,10 +516,11 @@ addActionHandler('setPrivacySettings', async (global, actions, payload): Promise
return;
}
const rules = buildInputPrivacyRules(global, {
const rules = buildApiInputPrivacyRules(global, {
visibility: settings.visibility,
allowedIds: isAllowList ? contactsIds : [...settings.allowUserIds, ...settings.allowChatIds],
deniedIds: !isAllowList ? contactsIds : [...settings.blockUserIds, ...settings.blockChatIds],
isUnspecified: settings.isUnspecified,
allowedIds: isAllowList ? updatedIds : [...settings.allowUserIds, ...settings.allowChatIds],
blockedIds: !isAllowList ? updatedIds : [...settings.blockUserIds, ...settings.blockChatIds],
});
const result = await callApi('setPrivacySettings', privacyKey, rules);
@ -537,74 +543,6 @@ addActionHandler('setPrivacySettings', async (global, actions, payload): Promise
setGlobal(global);
});
function buildInputPrivacyRules(global: GlobalState, {
visibility,
allowedIds,
deniedIds,
}: {
visibility: PrivacyVisibility;
allowedIds: string[];
deniedIds: string[];
}): InputPrivacyRules {
const {
users: { byId: usersById },
chats: { byId: chatsById },
} = global;
const rules: InputPrivacyRules = {
visibility,
};
let users: InputPrivacyContact[];
let chats: InputPrivacyContact[];
const collectUsers = (userId: string) => {
if (!isUserId(userId)) {
return undefined;
}
const { id, accessHash } = usersById[userId] || {};
if (!id) {
return undefined;
}
return { id, accessHash };
};
const collectChats = (userId: string) => {
if (isUserId(userId)) {
return undefined;
}
const chat = chatsById[userId];
return chat ? { id: chat.id } : undefined;
};
if (visibility === 'contacts' || visibility === 'nobody') {
users = allowedIds.map(collectUsers).filter(Boolean) as InputPrivacyContact[];
chats = allowedIds.map(collectChats).filter(Boolean) as InputPrivacyContact[];
if (users.length > 0) {
rules.allowedUsers = users;
}
if (chats.length > 0) {
rules.allowedChats = chats;
}
}
if (visibility === 'everybody' || visibility === 'contacts') {
users = deniedIds.map(collectUsers).filter(Boolean) as InputPrivacyContact[];
chats = deniedIds.map(collectChats).filter(Boolean) as InputPrivacyContact[];
if (users.length > 0) {
rules.blockedUsers = users;
}
if (chats.length > 0) {
rules.blockedChats = chats;
}
}
return rules;
}
addActionHandler('updateIsOnline', (global, actions, payload): ActionReturnType => {
if (global.connectionState !== 'connectionStateReady') return;
callApi('updateIsOnline', payload);

View File

@ -6,7 +6,7 @@ import { buildCollectionByKey } from '../../../util/iteratees';
import { translate } from '../../../util/langProvider';
import { getServerTime } from '../../../util/serverTime';
import { callApi } from '../../../api/gramjs';
import { getStoryKey } from '../../helpers';
import { buildApiInputPrivacyRules, getStoryKey } from '../../helpers';
import { addActionHandler, getGlobal, setGlobal } from '../../index';
import {
addStories,
@ -378,13 +378,19 @@ addActionHandler('editStoryPrivacy', (global, actions, payload): ActionReturnTyp
privacy,
} = payload;
const allowedUserList = privacy.allowUserIds?.map((userId) => selectUser(global, userId)).filter(Boolean);
const deniedUserList = privacy.blockUserIds?.map((userId) => selectUser(global, userId)).filter(Boolean);
const allowedIds = [...privacy.allowUserIds, ...privacy.allowChatIds];
const blockedIds = [...privacy.blockUserIds, ...privacy.blockChatIds];
const inputPrivacy = buildApiInputPrivacyRules(global, {
visibility: privacy.visibility,
isUnspecified: privacy.isUnspecified,
allowedIds,
blockedIds,
});
void callApi('editStoryPrivacy', {
id: storyId,
visibility: privacy.visibility,
allowedUserList,
deniedUserList,
privacy: inputPrivacy,
});
});

View File

@ -9,3 +9,4 @@ export * from './reactions';
export * from './bots';
export * from './media';
export * from './symbols';
export * from './misc';

View File

@ -0,0 +1,36 @@
import type { ApiInputPrivacyRules, PrivacyVisibility } from '../../types';
import type { GlobalState } from '../types';
import { partition } from '../../util/iteratees';
import { isUserId } from './chats';
export function buildApiInputPrivacyRules(global: GlobalState, {
visibility,
isUnspecified,
allowedIds,
blockedIds,
}: {
visibility: PrivacyVisibility;
isUnspecified?: boolean;
allowedIds: string[];
blockedIds: string[];
}): ApiInputPrivacyRules {
const {
users: { byId: usersById },
chats: { byId: chatsById },
} = global;
const [allowedUserIds, allowedChatIds] = partition(allowedIds, isUserId);
const [blockedUserIds, blockedChatIds] = partition(blockedIds, isUserId);
const rules: ApiInputPrivacyRules = {
visibility,
isUnspecified,
allowedUsers: allowedUserIds.map((userId) => usersById[userId]).filter(Boolean),
allowedChats: allowedChatIds.map((chatId) => chatsById[chatId]).filter(Boolean),
blockedUsers: blockedUserIds.map((userId) => usersById[userId]).filter(Boolean),
blockedChats: blockedChatIds.map((chatId) => chatsById[chatId]).filter(Boolean),
};
return rules;
}

View File

@ -1064,7 +1064,7 @@ export interface ActionPayloads {
setPrivacySettings: {
privacyKey: ApiPrivacyKey;
isAllowList: boolean;
contactsIds: string[];
updatedIds: string[];
};
loadNotificationExceptions: undefined;
setThemeSettings: { theme: ThemeKey } & Partial<IThemeSettings>;

File diff suppressed because it is too large Load Diff

View File

@ -3,8 +3,8 @@ $icons-font: "icons";
@font-face {
font-family: $icons-font;
src: url("./icons.woff2?2fc8ce731efb721947ab7acfba88eb91") format("woff2"),
url("./icons.woff?2fc8ce731efb721947ab7acfba88eb91") format("woff");
src: url("./icons.woff2?2e8e2fec4b27141c4d298083615a0665") format("woff2"),
url("./icons.woff?2e8e2fec4b27141c4d298083615a0665") format("woff");
font-weight: normal;
font-style: normal;
font-display: block;
@ -52,204 +52,206 @@ $icons-map: (
"arrow-down": "\f10f",
"arrow-left": "\f110",
"arrow-right": "\f111",
"attach": "\f112",
"avatar-archived-chats": "\f113",
"avatar-deleted-account": "\f114",
"avatar-saved-messages": "\f115",
"bold": "\f116",
"bot-command": "\f117",
"bot-commands-filled": "\f118",
"bots": "\f119",
"bug": "\f11a",
"calendar-filter": "\f11b",
"calendar": "\f11c",
"camera-add": "\f11d",
"camera": "\f11e",
"car": "\f11f",
"card": "\f120",
"channel-filled": "\f121",
"channel": "\f122",
"channelviews": "\f123",
"chat-badge": "\f124",
"chats-badge": "\f125",
"check": "\f126",
"close-circle": "\f127",
"close-topic": "\f128",
"close": "\f129",
"cloud-download": "\f12a",
"collapse": "\f12b",
"colorize": "\f12c",
"comments-sticker": "\f12d",
"comments": "\f12e",
"copy-media": "\f12f",
"copy": "\f130",
"darkmode": "\f131",
"data": "\f132",
"delete-filled": "\f133",
"delete-left": "\f134",
"delete-user": "\f135",
"delete": "\f136",
"document": "\f137",
"double-badge": "\f138",
"down": "\f139",
"download": "\f13a",
"eats": "\f13b",
"edit": "\f13c",
"email": "\f13d",
"enter": "\f13e",
"expand": "\f13f",
"eye-closed-outline": "\f140",
"eye-closed": "\f141",
"eye-outline": "\f142",
"eye": "\f143",
"favorite-filled": "\f144",
"favorite": "\f145",
"file-badge": "\f146",
"flag": "\f147",
"folder-badge": "\f148",
"folder": "\f149",
"fontsize": "\f14a",
"forums": "\f14b",
"forward": "\f14c",
"fullscreen": "\f14d",
"gifs": "\f14e",
"gift": "\f14f",
"group-filled": "\f150",
"group": "\f151",
"grouped-disable": "\f152",
"grouped": "\f153",
"hand-stop": "\f154",
"hashtag": "\f155",
"heart-outline": "\f156",
"heart": "\f157",
"help": "\f158",
"info-filled": "\f159",
"info": "\f15a",
"install": "\f15b",
"italic": "\f15c",
"key": "\f15d",
"keyboard": "\f15e",
"lamp": "\f15f",
"language": "\f160",
"large-pause": "\f161",
"large-play": "\f162",
"link-badge": "\f163",
"link-broken": "\f164",
"link": "\f165",
"location": "\f166",
"lock-badge": "\f167",
"lock": "\f168",
"logout": "\f169",
"loop": "\f16a",
"mention": "\f16b",
"message-failed": "\f16c",
"message-pending": "\f16d",
"message-read": "\f16e",
"message-succeeded": "\f16f",
"message": "\f170",
"microphone-alt": "\f171",
"microphone": "\f172",
"monospace": "\f173",
"more-circle": "\f174",
"more": "\f175",
"mute": "\f176",
"muted": "\f177",
"new-chat-filled": "\f178",
"next": "\f179",
"noise-suppression": "\f17a",
"non-contacts": "\f17b",
"open-in-new-tab": "\f17c",
"password-off": "\f17d",
"pause": "\f17e",
"permissions": "\f17f",
"phone-discard-outline": "\f180",
"phone-discard": "\f181",
"phone": "\f182",
"photo": "\f183",
"pin-badge": "\f184",
"pin-list": "\f185",
"pin": "\f186",
"pinned-chat": "\f187",
"pinned-message": "\f188",
"pip": "\f189",
"play-story": "\f18a",
"play": "\f18b",
"poll": "\f18c",
"premium": "\f18d",
"previous": "\f18e",
"readchats": "\f18f",
"recent": "\f190",
"reload": "\f191",
"remove": "\f192",
"reopen-topic": "\f193",
"replace": "\f194",
"replies": "\f195",
"reply-filled": "\f196",
"reply": "\f197",
"revote": "\f198",
"save-story": "\f199",
"saved-messages": "\f19a",
"schedule": "\f19b",
"search": "\f19c",
"select": "\f19d",
"send-outline": "\f19e",
"send": "\f19f",
"settings-filled": "\f1a0",
"settings": "\f1a1",
"share-filled": "\f1a2",
"share-screen-outlined": "\f1a3",
"share-screen-stop": "\f1a4",
"share-screen": "\f1a5",
"sidebar": "\f1a6",
"skip-next": "\f1a7",
"skip-previous": "\f1a8",
"smallscreen": "\f1a9",
"smile": "\f1aa",
"sort": "\f1ab",
"speaker-muted-story": "\f1ac",
"speaker-outline": "\f1ad",
"speaker-story": "\f1ae",
"speaker": "\f1af",
"spoiler-disable": "\f1b0",
"spoiler": "\f1b1",
"sport": "\f1b2",
"stats": "\f1b3",
"stealth-future": "\f1b4",
"stealth-past": "\f1b5",
"stickers": "\f1b6",
"stop-raising-hand": "\f1b7",
"stop": "\f1b8",
"story-caption": "\f1b9",
"story-expired": "\f1ba",
"story-priority": "\f1bb",
"story-reply": "\f1bc",
"strikethrough": "\f1bd",
"timer": "\f1be",
"transcribe": "\f1bf",
"truck": "\f1c0",
"unarchive": "\f1c1",
"underlined": "\f1c2",
"unlock-badge": "\f1c3",
"unlock": "\f1c4",
"unmute": "\f1c5",
"unpin": "\f1c6",
"unread": "\f1c7",
"up": "\f1c8",
"user-filled": "\f1c9",
"user-online": "\f1ca",
"user": "\f1cb",
"video-outlined": "\f1cc",
"video-stop": "\f1cd",
"video": "\f1ce",
"voice-chat": "\f1cf",
"volume-1": "\f1d0",
"volume-2": "\f1d1",
"volume-3": "\f1d2",
"web": "\f1d3",
"webapp": "\f1d4",
"word-wrap": "\f1d5",
"zoom-in": "\f1d6",
"zoom-out": "\f1d7",
"ask-support": "\f112",
"attach": "\f113",
"avatar-archived-chats": "\f114",
"avatar-deleted-account": "\f115",
"avatar-saved-messages": "\f116",
"bold": "\f117",
"bot-command": "\f118",
"bot-commands-filled": "\f119",
"bots": "\f11a",
"bug": "\f11b",
"calendar-filter": "\f11c",
"calendar": "\f11d",
"camera-add": "\f11e",
"camera": "\f11f",
"car": "\f120",
"card": "\f121",
"channel-filled": "\f122",
"channel": "\f123",
"channelviews": "\f124",
"chat-badge": "\f125",
"chats-badge": "\f126",
"check": "\f127",
"close-circle": "\f128",
"close-topic": "\f129",
"close": "\f12a",
"cloud-download": "\f12b",
"collapse": "\f12c",
"colorize": "\f12d",
"comments-sticker": "\f12e",
"comments": "\f12f",
"copy-media": "\f130",
"copy": "\f131",
"darkmode": "\f132",
"data": "\f133",
"delete-filled": "\f134",
"delete-left": "\f135",
"delete-user": "\f136",
"delete": "\f137",
"document": "\f138",
"double-badge": "\f139",
"down": "\f13a",
"download": "\f13b",
"eats": "\f13c",
"edit": "\f13d",
"email": "\f13e",
"enter": "\f13f",
"expand": "\f140",
"eye-closed-outline": "\f141",
"eye-closed": "\f142",
"eye-outline": "\f143",
"eye": "\f144",
"favorite-filled": "\f145",
"favorite": "\f146",
"file-badge": "\f147",
"flag": "\f148",
"folder-badge": "\f149",
"folder": "\f14a",
"fontsize": "\f14b",
"forums": "\f14c",
"forward": "\f14d",
"fullscreen": "\f14e",
"gifs": "\f14f",
"gift": "\f150",
"group-filled": "\f151",
"group": "\f152",
"grouped-disable": "\f153",
"grouped": "\f154",
"hand-stop": "\f155",
"hashtag": "\f156",
"heart-outline": "\f157",
"heart": "\f158",
"help": "\f159",
"info-filled": "\f15a",
"info": "\f15b",
"install": "\f15c",
"italic": "\f15d",
"key": "\f15e",
"keyboard": "\f15f",
"lamp": "\f160",
"language": "\f161",
"large-pause": "\f162",
"large-play": "\f163",
"link-badge": "\f164",
"link-broken": "\f165",
"link": "\f166",
"location": "\f167",
"lock-badge": "\f168",
"lock": "\f169",
"logout": "\f16a",
"loop": "\f16b",
"mention": "\f16c",
"message-failed": "\f16d",
"message-pending": "\f16e",
"message-read": "\f16f",
"message-succeeded": "\f170",
"message": "\f171",
"microphone-alt": "\f172",
"microphone": "\f173",
"monospace": "\f174",
"more-circle": "\f175",
"more": "\f176",
"mute": "\f177",
"muted": "\f178",
"new-chat-filled": "\f179",
"next": "\f17a",
"noise-suppression": "\f17b",
"non-contacts": "\f17c",
"open-in-new-tab": "\f17d",
"password-off": "\f17e",
"pause": "\f17f",
"permissions": "\f180",
"phone-discard-outline": "\f181",
"phone-discard": "\f182",
"phone": "\f183",
"photo": "\f184",
"pin-badge": "\f185",
"pin-list": "\f186",
"pin": "\f187",
"pinned-chat": "\f188",
"pinned-message": "\f189",
"pip": "\f18a",
"play-story": "\f18b",
"play": "\f18c",
"poll": "\f18d",
"premium": "\f18e",
"previous": "\f18f",
"privacy-policy": "\f190",
"readchats": "\f191",
"recent": "\f192",
"reload": "\f193",
"remove": "\f194",
"reopen-topic": "\f195",
"replace": "\f196",
"replies": "\f197",
"reply-filled": "\f198",
"reply": "\f199",
"revote": "\f19a",
"save-story": "\f19b",
"saved-messages": "\f19c",
"schedule": "\f19d",
"search": "\f19e",
"select": "\f19f",
"send-outline": "\f1a0",
"send": "\f1a1",
"settings-filled": "\f1a2",
"settings": "\f1a3",
"share-filled": "\f1a4",
"share-screen-outlined": "\f1a5",
"share-screen-stop": "\f1a6",
"share-screen": "\f1a7",
"sidebar": "\f1a8",
"skip-next": "\f1a9",
"skip-previous": "\f1aa",
"smallscreen": "\f1ab",
"smile": "\f1ac",
"sort": "\f1ad",
"speaker-muted-story": "\f1ae",
"speaker-outline": "\f1af",
"speaker-story": "\f1b0",
"speaker": "\f1b1",
"spoiler-disable": "\f1b2",
"spoiler": "\f1b3",
"sport": "\f1b4",
"stats": "\f1b5",
"stealth-future": "\f1b6",
"stealth-past": "\f1b7",
"stickers": "\f1b8",
"stop-raising-hand": "\f1b9",
"stop": "\f1ba",
"story-caption": "\f1bb",
"story-expired": "\f1bc",
"story-priority": "\f1bd",
"story-reply": "\f1be",
"strikethrough": "\f1bf",
"timer": "\f1c0",
"transcribe": "\f1c1",
"truck": "\f1c2",
"unarchive": "\f1c3",
"underlined": "\f1c4",
"unlock-badge": "\f1c5",
"unlock": "\f1c6",
"unmute": "\f1c7",
"unpin": "\f1c8",
"unread": "\f1c9",
"up": "\f1ca",
"user-filled": "\f1cb",
"user-online": "\f1cc",
"user": "\f1cd",
"video-outlined": "\f1ce",
"video-stop": "\f1cf",
"video": "\f1d0",
"voice-chat": "\f1d1",
"volume-1": "\f1d2",
"volume-2": "\f1d3",
"volume-3": "\f1d4",
"web": "\f1d5",
"webapp": "\f1d6",
"word-wrap": "\f1d7",
"zoom-in": "\f1d8",
"zoom-out": "\f1d9",
);
.icon-active-sessions::before {
@ -303,6 +305,9 @@ $icons-map: (
.icon-arrow-right::before {
content: map.get($icons-map, "arrow-right");
}
.icon-ask-support::before {
content: map.get($icons-map, "ask-support");
}
.icon-attach::before {
content: map.get($icons-map, "attach");
}
@ -678,6 +683,9 @@ $icons-map: (
.icon-previous::before {
content: map.get($icons-map, "previous");
}
.icon-privacy-policy::before {
content: map.get($icons-map, "privacy-policy");
}
.icon-readchats::before {
content: map.get($icons-map, "readchats");
}

Binary file not shown.

Binary file not shown.

View File

@ -16,6 +16,7 @@ export type FontIconName =
| 'arrow-down'
| 'arrow-left'
| 'arrow-right'
| 'ask-support'
| 'attach'
| 'avatar-archived-chats'
| 'avatar-deleted-account'
@ -141,6 +142,7 @@ export type FontIconName =
| 'poll'
| 'premium'
| 'previous'
| 'privacy-policy'
| 'readchats'
| 'recent'
| 'reload'

View File

@ -3,9 +3,10 @@ import type { TeactNode } from '../lib/teact/teact';
import type {
ApiBotInlineMediaResult, ApiBotInlineResult, ApiBotInlineSwitchPm,
ApiBotInlineSwitchWebview,
ApiChat,
ApiChatInviteImporter,
ApiExportedInvite,
ApiLanguage, ApiMessage, ApiReaction, ApiStickerSet,
ApiLanguage, ApiMessage, ApiReaction, ApiStickerSet, ApiUser,
} from '../api/types';
export type TextPart = TeactNode;
@ -112,23 +113,20 @@ export interface ISettings extends NotifySettings, Record<string, any> {
export interface ApiPrivacySettings {
visibility: PrivacyVisibility;
isUnspecified?: boolean;
allowUserIds: string[];
allowChatIds: string[];
blockUserIds: string[];
blockChatIds: string[];
}
export interface InputPrivacyContact {
id: string;
accessHash?: string;
}
export interface InputPrivacyRules {
export interface ApiInputPrivacyRules {
visibility: PrivacyVisibility;
allowedUsers?: InputPrivacyContact[];
allowedChats?: InputPrivacyContact[];
blockedUsers?: InputPrivacyContact[];
blockedChats?: InputPrivacyContact[];
isUnspecified?: boolean;
allowedUsers?: ApiUser[];
allowedChats?: ApiChat[];
blockedUsers?: ApiUser[];
blockedChats?: ApiChat[];
}
export type IAnchorPosition = {
@ -173,8 +171,10 @@ export enum SettingsScreens {
GeneralChatBackgroundColor,
Privacy,
PrivacyPhoneNumber,
PrivacyAddByPhone,
PrivacyLastSeen,
PrivacyProfilePhoto,
PrivacyBio,
PrivacyPhoneCall,
PrivacyPhoneP2P,
PrivacyForwarding,
@ -186,6 +186,8 @@ export enum SettingsScreens {
PrivacyLastSeenDeniedContacts,
PrivacyProfilePhotoAllowedContacts,
PrivacyProfilePhotoDeniedContacts,
PrivacyBioAllowedContacts,
PrivacyBioDeniedContacts,
PrivacyPhoneCallAllowedContacts,
PrivacyPhoneCallDeniedContacts,
PrivacyPhoneP2PAllowedContacts,
@ -354,10 +356,9 @@ export type ProfileTabType = (
'members' | 'commonChats' | 'media' | 'documents' | 'links' | 'audio' | 'voice' | 'stories' | 'storiesArchive'
);
export type SharedMediaType = 'media' | 'documents' | 'links' | 'audio' | 'voice';
export type ApiPrivacyKey = 'phoneNumber' | 'lastSeen' | 'profilePhoto' | 'voiceMessages' |
'forwards' | 'chatInvite' | 'phoneCall' | 'phoneP2P';
export type PrivacyVisibility = 'everybody' | 'contacts' | 'closeFriends' | 'selectedContacts' | 'nonContacts' |
'nobody';
export type ApiPrivacyKey = 'phoneNumber' | 'addByPhone' | 'lastSeen' | 'profilePhoto' | 'voiceMessages' |
'forwards' | 'chatInvite' | 'phoneCall' | 'phoneP2P' | 'bio';
export type PrivacyVisibility = 'everybody' | 'contacts' | 'closeFriends' | 'nonContacts' | 'nobody';
export enum ProfileState {
Profile,