Profile: GIFs & Main Tab (#6336)
This commit is contained in:
parent
1be16bf765
commit
5e679218e2
@ -5,7 +5,7 @@ module.exports = {
|
||||
fontTypes: ['woff2', 'woff'],
|
||||
assetTypes: ['scss', 'ts'],
|
||||
tag: '',
|
||||
// Use a custom Handlebars template
|
||||
normalize: true,
|
||||
templates: {
|
||||
scss: './dev/icons.scss.hbs',
|
||||
},
|
||||
|
||||
2
src/@types/global.d.ts
vendored
2
src/@types/global.d.ts
vendored
@ -48,6 +48,8 @@ type AnyToVoidFunction = (...args: any[]) => void;
|
||||
type BooleanToVoidFunction = (value: boolean) => void;
|
||||
type NoneToVoidFunction = () => void;
|
||||
|
||||
type StringAutocomplete<T> = T | (string & {});
|
||||
|
||||
type Complete<T> = {
|
||||
[P in keyof Required<T>]: Pick<T, P> extends Required<Pick<T, P>> ? T[P] : (T[P] | undefined);
|
||||
};
|
||||
|
||||
@ -29,14 +29,17 @@ import { getServerTimeOffset } from '../../../util/serverTime';
|
||||
import { addPhotoToLocalDb, addUserToLocalDb } from '../helpers/localDb';
|
||||
import { serializeBytes } from '../helpers/misc';
|
||||
import {
|
||||
buildApiBotVerification, buildApiFormattedText, buildApiPhoto, buildApiUsernames, buildAvatarPhotoId,
|
||||
buildApiFormattedText, buildApiPhoto, buildApiUsernames,
|
||||
} from './common';
|
||||
import { omitVirtualClassFields } from './helpers';
|
||||
import { buildApiPeerNotifySettings, buildApiRestrictionReasons } from './misc';
|
||||
import { buildApiRestrictionReasons } from './misc';
|
||||
import {
|
||||
buildApiBotVerification,
|
||||
buildApiEmojiStatus,
|
||||
buildApiPeerColor,
|
||||
buildApiPeerId,
|
||||
buildApiPeerNotifySettings,
|
||||
buildAvatarPhotoId,
|
||||
getApiChatIdFromMtpPeer,
|
||||
isMtpPeerChat,
|
||||
isMtpPeerUser,
|
||||
|
||||
@ -3,7 +3,6 @@ import type { Entity } from '../../../lib/gramjs/types';
|
||||
import { strippedPhotoToJpg } from '../../../lib/gramjs/Utils';
|
||||
|
||||
import type {
|
||||
ApiBotVerification,
|
||||
ApiFormattedText,
|
||||
ApiMessageEntity,
|
||||
ApiMessageEntityDefault,
|
||||
@ -293,19 +292,3 @@ export function buildApiMessageEntity(entity: GramJs.TypeMessageEntity): ApiMess
|
||||
length,
|
||||
};
|
||||
}
|
||||
|
||||
export function buildAvatarPhotoId(photo: GramJs.TypeUserProfilePhoto | GramJs.TypeChatPhoto) {
|
||||
if ('photoId' in photo) {
|
||||
return photo.photoId.toString();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function buildApiBotVerification(botVerification: GramJs.BotVerification): ApiBotVerification {
|
||||
return {
|
||||
botId: buildApiPeerId(botVerification.botId, 'user'),
|
||||
iconId: botVerification.icon.toString(),
|
||||
description: botVerification.description,
|
||||
};
|
||||
}
|
||||
|
||||
@ -7,9 +7,6 @@ import type {
|
||||
ApiCountry,
|
||||
ApiLanguage,
|
||||
ApiOldLangString,
|
||||
ApiPeerColors,
|
||||
ApiPeerNotifySettings,
|
||||
ApiPeerProfileColorSet,
|
||||
ApiPrivacyKey,
|
||||
ApiRestrictionReason,
|
||||
ApiSession,
|
||||
@ -20,9 +17,8 @@ import type {
|
||||
LangPackStringValue,
|
||||
} from '../../types';
|
||||
|
||||
import { numberToHexColor } from '../../../util/colors';
|
||||
import {
|
||||
buildCollectionByCallback, omit, omitUndefined, pick,
|
||||
omit, omitUndefined, pick,
|
||||
} from '../../../util/iteratees';
|
||||
import { toJSNumber } from '../../../util/numbers';
|
||||
import { addUserToLocalDb } from '../helpers/localDb';
|
||||
@ -111,23 +107,6 @@ export function buildPrivacyKey(key: GramJs.TypePrivacyKey): ApiPrivacyKey | und
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function buildApiPeerNotifySettings(
|
||||
notifySettings: GramJs.TypePeerNotifySettings,
|
||||
): ApiPeerNotifySettings {
|
||||
const {
|
||||
silent, muteUntil, showPreviews, otherSound,
|
||||
} = notifySettings;
|
||||
|
||||
const hasSound = !(otherSound instanceof GramJs.NotificationSoundNone);
|
||||
|
||||
return {
|
||||
hasSound,
|
||||
isSilentPosting: silent,
|
||||
mutedUntil: muteUntil,
|
||||
shouldShowPreviews: showPreviews,
|
||||
};
|
||||
}
|
||||
|
||||
function buildApiCountry(country: GramJs.help.Country, code: GramJs.help.CountryCode) {
|
||||
const {
|
||||
hidden, iso2, defaultName, name,
|
||||
@ -295,46 +274,6 @@ export function buildApiLanguage(lang: GramJs.TypeLangPackLanguage): ApiLanguage
|
||||
};
|
||||
}
|
||||
|
||||
function buildApiPeerColorSet(colorSet: GramJs.help.PeerColorSet) {
|
||||
return colorSet.colors.map((color) => numberToHexColor(color));
|
||||
}
|
||||
|
||||
function buildApiPeerProfileColorSet(colorSet: GramJs.help.PeerColorProfileSet): ApiPeerProfileColorSet {
|
||||
return {
|
||||
paletteColors: colorSet.paletteColors.map((color) => numberToHexColor(color)),
|
||||
bgColors: colorSet.bgColors.map((color) => numberToHexColor(color)),
|
||||
storyColors: colorSet.storyColors.map((color) => numberToHexColor(color)),
|
||||
};
|
||||
}
|
||||
|
||||
export function buildApiPeerColors(wrapper: GramJs.help.TypePeerColors): ApiPeerColors['general'] | undefined {
|
||||
if (!(wrapper instanceof GramJs.help.PeerColors)) return undefined;
|
||||
|
||||
return buildCollectionByCallback(wrapper.colors, (color) => {
|
||||
return [color.colorId, {
|
||||
isHidden: color.hidden,
|
||||
colors: color.colors instanceof GramJs.help.PeerColorSet
|
||||
? buildApiPeerColorSet(color.colors) : undefined,
|
||||
darkColors: color.darkColors instanceof GramJs.help.PeerColorSet
|
||||
? buildApiPeerColorSet(color.darkColors) : undefined,
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
export function buildApiPeerProfileColors(wrapper: GramJs.help.TypePeerColors): ApiPeerColors['profile'] | undefined {
|
||||
if (!(wrapper instanceof GramJs.help.PeerColors)) return undefined;
|
||||
|
||||
return buildCollectionByCallback(wrapper.colors, (color) => {
|
||||
return [color.colorId, {
|
||||
isHidden: color.hidden,
|
||||
colors: color.colors instanceof GramJs.help.PeerColorProfileSet
|
||||
? buildApiPeerProfileColorSet(color.colors) : undefined,
|
||||
darkColors: color.darkColors instanceof GramJs.help.PeerColorProfileSet
|
||||
? buildApiPeerProfileColorSet(color.darkColors) : undefined,
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
export function buildApiTimezone(timezone: GramJs.TypeTimezone): ApiTimezone {
|
||||
const { id, name, utcOffset } = timezone;
|
||||
return {
|
||||
|
||||
@ -1,9 +1,18 @@
|
||||
import { Api as GramJs } from '../../../lib/gramjs';
|
||||
|
||||
import type { ApiEmojiStatusType, ApiPeerColor } from '../../types';
|
||||
import type {
|
||||
ApiBotVerification,
|
||||
ApiEmojiStatusType,
|
||||
ApiPeerColor,
|
||||
ApiPeerColors,
|
||||
ApiPeerNotifySettings,
|
||||
ApiPeerProfileColorSet,
|
||||
ApiProfileTab,
|
||||
} from '../../types';
|
||||
|
||||
import { CHANNEL_ID_BASE } from '../../../config';
|
||||
import { numberToHexColor } from '../../../util/colors';
|
||||
import { buildCollectionByCallback } from '../../../util/iteratees';
|
||||
|
||||
type TypePeerOrInput = GramJs.TypePeer | GramJs.TypeInputPeer | GramJs.TypeInputUser | GramJs.TypeInputChannel;
|
||||
|
||||
@ -49,6 +58,46 @@ export function buildApiPeerColor(peerColor: GramJs.TypePeerColor): ApiPeerColor
|
||||
};
|
||||
}
|
||||
|
||||
function buildApiPeerColorSet(colorSet: GramJs.help.PeerColorSet) {
|
||||
return colorSet.colors.map((color) => numberToHexColor(color));
|
||||
}
|
||||
|
||||
function buildApiPeerProfileColorSet(colorSet: GramJs.help.PeerColorProfileSet): ApiPeerProfileColorSet {
|
||||
return {
|
||||
paletteColors: colorSet.paletteColors.map((color) => numberToHexColor(color)),
|
||||
bgColors: colorSet.bgColors.map((color) => numberToHexColor(color)),
|
||||
storyColors: colorSet.storyColors.map((color) => numberToHexColor(color)),
|
||||
};
|
||||
}
|
||||
|
||||
export function buildApiPeerColors(wrapper: GramJs.help.TypePeerColors): ApiPeerColors['general'] | undefined {
|
||||
if (!(wrapper instanceof GramJs.help.PeerColors)) return undefined;
|
||||
|
||||
return buildCollectionByCallback(wrapper.colors, (color) => {
|
||||
return [color.colorId, {
|
||||
isHidden: color.hidden,
|
||||
colors: color.colors instanceof GramJs.help.PeerColorSet
|
||||
? buildApiPeerColorSet(color.colors) : undefined,
|
||||
darkColors: color.darkColors instanceof GramJs.help.PeerColorSet
|
||||
? buildApiPeerColorSet(color.darkColors) : undefined,
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
export function buildApiPeerProfileColors(wrapper: GramJs.help.TypePeerColors): ApiPeerColors['profile'] | undefined {
|
||||
if (!(wrapper instanceof GramJs.help.PeerColors)) return undefined;
|
||||
|
||||
return buildCollectionByCallback(wrapper.colors, (color) => {
|
||||
return [color.colorId, {
|
||||
isHidden: color.hidden,
|
||||
colors: color.colors instanceof GramJs.help.PeerColorProfileSet
|
||||
? buildApiPeerProfileColorSet(color.colors) : undefined,
|
||||
darkColors: color.darkColors instanceof GramJs.help.PeerColorProfileSet
|
||||
? buildApiPeerProfileColorSet(color.darkColors) : undefined,
|
||||
}];
|
||||
});
|
||||
}
|
||||
|
||||
export function buildApiEmojiStatus(mtpEmojiStatus: GramJs.TypeEmojiStatus):
|
||||
ApiEmojiStatusType | undefined {
|
||||
if (mtpEmojiStatus instanceof GramJs.EmojiStatus) {
|
||||
@ -77,3 +126,61 @@ ApiEmojiStatusType | undefined {
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function buildAvatarPhotoId(photo: GramJs.TypeUserProfilePhoto | GramJs.TypeChatPhoto) {
|
||||
if ('photoId' in photo) {
|
||||
return photo.photoId.toString();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function buildApiBotVerification(botVerification: GramJs.BotVerification): ApiBotVerification {
|
||||
return {
|
||||
botId: buildApiPeerId(botVerification.botId, 'user'),
|
||||
iconId: botVerification.icon.toString(),
|
||||
description: botVerification.description,
|
||||
};
|
||||
}
|
||||
|
||||
export function buildApiPeerNotifySettings(
|
||||
notifySettings: GramJs.TypePeerNotifySettings,
|
||||
): ApiPeerNotifySettings {
|
||||
const {
|
||||
silent, muteUntil, showPreviews, otherSound,
|
||||
} = notifySettings;
|
||||
|
||||
const hasSound = !(otherSound instanceof GramJs.NotificationSoundNone);
|
||||
|
||||
return {
|
||||
hasSound,
|
||||
isSilentPosting: silent,
|
||||
mutedUntil: muteUntil,
|
||||
shouldShowPreviews: showPreviews,
|
||||
};
|
||||
}
|
||||
|
||||
export function buildApiProfileTab(profileTab: GramJs.TypeProfileTab): ApiProfileTab {
|
||||
switch (profileTab.className) {
|
||||
case 'ProfileTabPosts':
|
||||
return 'stories';
|
||||
case 'ProfileTabGifts':
|
||||
return 'gifts';
|
||||
case 'ProfileTabMedia':
|
||||
return 'media';
|
||||
case 'ProfileTabFiles':
|
||||
return 'documents';
|
||||
case 'ProfileTabMusic':
|
||||
return 'audio';
|
||||
case 'ProfileTabVoice':
|
||||
return 'voice';
|
||||
case 'ProfileTabLinks':
|
||||
return 'links';
|
||||
case 'ProfileTabGifs':
|
||||
return 'gif';
|
||||
default: {
|
||||
const _exhaustiveCheck: never = profileTab;
|
||||
return _exhaustiveCheck;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,9 +16,9 @@ import type {
|
||||
TypeStatisticsGraph,
|
||||
} from '../../types';
|
||||
|
||||
import { buildApiUsernames, buildAvatarPhotoId } from './common';
|
||||
import { buildApiUsernames } from './common';
|
||||
import { buildApiCurrencyAmount } from './payments';
|
||||
import { buildApiPeerId, getApiChatIdFromMtpPeer } from './peers';
|
||||
import { buildApiPeerId, buildAvatarPhotoId, getApiChatIdFromMtpPeer } from './peers';
|
||||
|
||||
export function buildChannelStatistics(stats: GramJs.stats.BroadcastStats): ApiChannelStatistics {
|
||||
return {
|
||||
|
||||
@ -14,11 +14,18 @@ import { toJSNumber } from '../../../util/numbers';
|
||||
import { buildApiBotInfo } from './bots';
|
||||
import { buildApiBusinessIntro, buildApiBusinessLocation, buildApiBusinessWorkHours } from './business';
|
||||
import {
|
||||
buildApiBotVerification, buildApiPhoto, buildApiUsernames, buildAvatarPhotoId,
|
||||
buildApiPhoto, buildApiUsernames,
|
||||
} from './common';
|
||||
import { buildApiDisallowedGiftsSettings } from './gifts';
|
||||
import { omitVirtualClassFields } from './helpers';
|
||||
import { buildApiEmojiStatus, buildApiPeerColor, buildApiPeerId } from './peers';
|
||||
import {
|
||||
buildApiBotVerification,
|
||||
buildApiEmojiStatus,
|
||||
buildApiPeerColor,
|
||||
buildApiPeerId,
|
||||
buildApiProfileTab,
|
||||
buildAvatarPhotoId,
|
||||
} from './peers';
|
||||
|
||||
export function buildApiUserFullInfo(mtpUserFull: GramJs.users.UserFull): ApiUserFullInfo {
|
||||
const {
|
||||
@ -29,7 +36,7 @@ export function buildApiUserFullInfo(mtpUserFull: GramJs.users.UserFull): ApiUse
|
||||
contactRequirePremium, businessWorkHours, businessLocation, businessIntro,
|
||||
birthday, personalChannelId, personalChannelMessage, sponsoredEnabled, stargiftsCount, botVerification,
|
||||
botCanManageEmojiStatus, settings, sendPaidMessagesStars, displayGiftsButton, disallowedGifts,
|
||||
starsRating, starsMyPendingRating, starsMyPendingRatingDate,
|
||||
starsRating, starsMyPendingRating, starsMyPendingRatingDate, mainTab,
|
||||
},
|
||||
users,
|
||||
} = mtpUserFull;
|
||||
@ -68,6 +75,7 @@ export function buildApiUserFullInfo(mtpUserFull: GramJs.users.UserFull): ApiUse
|
||||
hasScheduledMessages: hasScheduled,
|
||||
paidMessagesStars: toJSNumber(sendPaidMessagesStars),
|
||||
settings: buildApiPeerSettings(settings),
|
||||
mainTab: mainTab && buildApiProfileTab(mainTab),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -23,6 +23,7 @@ import type {
|
||||
ApiPoll,
|
||||
ApiPremiumGiftCodeOption,
|
||||
ApiPrivacyKey,
|
||||
ApiProfileTab,
|
||||
ApiReactionWithPaid,
|
||||
ApiReportReason,
|
||||
ApiRequestInputInvoice,
|
||||
@ -980,3 +981,28 @@ export function buildInputSavedStarGift(inputGift: ApiRequestInputSavedStarGift)
|
||||
savedId: BigInt(inputGift.savedId),
|
||||
});
|
||||
}
|
||||
|
||||
export function buildInputProfileTab(profileTab: ApiProfileTab) {
|
||||
switch (profileTab) {
|
||||
case 'stories':
|
||||
return new GramJs.ProfileTabPosts();
|
||||
case 'gifts':
|
||||
return new GramJs.ProfileTabGifts();
|
||||
case 'media':
|
||||
return new GramJs.ProfileTabMedia();
|
||||
case 'documents':
|
||||
return new GramJs.ProfileTabFiles();
|
||||
case 'audio':
|
||||
return new GramJs.ProfileTabMusic();
|
||||
case 'voice':
|
||||
return new GramJs.ProfileTabVoice();
|
||||
case 'links':
|
||||
return new GramJs.ProfileTabLinks();
|
||||
case 'gif':
|
||||
return new GramJs.ProfileTabGifs();
|
||||
default: {
|
||||
const _exhaustiveCheck: never = profileTab;
|
||||
return _exhaustiveCheck;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,17 @@
|
||||
import { Api as GramJs } from '../../../lib/gramjs';
|
||||
|
||||
import type {
|
||||
ApiPeer, ApiPhoto, ApiReportReason,
|
||||
ApiPeer, ApiPhoto, ApiProfileTab, ApiReportReason,
|
||||
} from '../../types';
|
||||
|
||||
import { buildApiChatLink } from '../apiBuilders/misc';
|
||||
import { buildInputPeer, buildInputPhoto, buildInputReportReason, DEFAULT_PRIMITIVES } from '../gramjsBuilders';
|
||||
import {
|
||||
buildInputPeer,
|
||||
buildInputPhoto,
|
||||
buildInputProfileTab,
|
||||
buildInputReportReason,
|
||||
DEFAULT_PRIMITIVES,
|
||||
} from '../gramjsBuilders';
|
||||
import { invokeRequest } from './client';
|
||||
|
||||
export async function reportPeer({
|
||||
@ -124,3 +130,11 @@ export function setAccountTTL({ days }: { days: number }) {
|
||||
shouldReturnTrue: true,
|
||||
});
|
||||
}
|
||||
|
||||
export function setAccountMainProfileTab({ tab }: { tab: ApiProfileTab }) {
|
||||
return invokeRequest(new GramJs.account.SetMainProfileTab({
|
||||
tab: buildInputProfileTab(tab),
|
||||
}), {
|
||||
shouldReturnTrue: true,
|
||||
});
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@ import type {
|
||||
ApiPeer,
|
||||
ApiPeerNotifySettings,
|
||||
ApiPhoto,
|
||||
ApiProfileTab,
|
||||
ApiTopic,
|
||||
ApiUser,
|
||||
ApiUserStatus,
|
||||
@ -51,10 +52,15 @@ import {
|
||||
buildChatMembers,
|
||||
getPeerKey,
|
||||
} from '../apiBuilders/chats';
|
||||
import { buildApiBotVerification, buildApiPhoto } from '../apiBuilders/common';
|
||||
import { buildApiPhoto } from '../apiBuilders/common';
|
||||
import { buildApiMessage, buildMessageDraft } from '../apiBuilders/messages';
|
||||
import { buildApiPeerNotifySettings } from '../apiBuilders/misc';
|
||||
import { buildApiPeerId, getApiChatIdFromMtpPeer } from '../apiBuilders/peers';
|
||||
import {
|
||||
buildApiBotVerification,
|
||||
buildApiPeerId,
|
||||
buildApiPeerNotifySettings,
|
||||
buildApiProfileTab,
|
||||
getApiChatIdFromMtpPeer,
|
||||
} from '../apiBuilders/peers';
|
||||
import { buildStickerSet } from '../apiBuilders/symbols';
|
||||
import { buildApiPeerSettings, buildApiUser, buildApiUserStatuses } from '../apiBuilders/users';
|
||||
import {
|
||||
@ -66,6 +72,7 @@ import {
|
||||
buildInputChatReactions,
|
||||
buildInputPeer,
|
||||
buildInputPhoto,
|
||||
buildInputProfileTab,
|
||||
buildInputReplyTo,
|
||||
buildInputSuggestedPost,
|
||||
buildInputUser,
|
||||
@ -654,6 +661,7 @@ async function getFullChannelInfo(
|
||||
stargiftsCount,
|
||||
stargiftsAvailable,
|
||||
paidMessagesAvailable,
|
||||
mainTab,
|
||||
} = result.fullChat;
|
||||
|
||||
if (chatPhoto) {
|
||||
@ -753,6 +761,7 @@ async function getFullChannelInfo(
|
||||
starGiftCount: stargiftsCount,
|
||||
areStarGiftsAvailable: Boolean(stargiftsAvailable),
|
||||
arePaidMessagesAvailable: paidMessagesAvailable,
|
||||
mainTab: mainTab && buildApiProfileTab(mainTab),
|
||||
},
|
||||
chats,
|
||||
userStatusesById: statusesById,
|
||||
@ -2092,3 +2101,12 @@ export function toggleAutoTranslation({
|
||||
shouldReturnTrue: true,
|
||||
});
|
||||
}
|
||||
|
||||
export function setChannelMainProfileTab({ chat, tab }: { chat: ApiChat; tab: ApiProfileTab }) {
|
||||
return invokeRequest(new GramJs.channels.SetMainProfileTab({
|
||||
channel: buildInputChannel(chat.id, chat.accessHash),
|
||||
tab: buildInputProfileTab(tab),
|
||||
}), {
|
||||
shouldReturnTrue: true,
|
||||
});
|
||||
}
|
||||
|
||||
@ -1494,6 +1494,9 @@ export async function searchMessagesInChat({
|
||||
case 'profilePhoto':
|
||||
filter = new GramJs.InputMessagesFilterChatPhotos();
|
||||
break;
|
||||
case 'gif':
|
||||
filter = new GramJs.InputMessagesFilterGif();
|
||||
break;
|
||||
case 'text':
|
||||
default: {
|
||||
filter = new GramJs.InputMessagesFilterEmpty();
|
||||
|
||||
@ -31,9 +31,6 @@ import {
|
||||
buildApiConfig,
|
||||
buildApiCountryList,
|
||||
buildApiLanguage,
|
||||
buildApiPeerColors,
|
||||
buildApiPeerNotifySettings,
|
||||
buildApiPeerProfileColors,
|
||||
buildApiSession,
|
||||
buildApiTimezone,
|
||||
buildApiWallpaper,
|
||||
@ -41,7 +38,12 @@ import {
|
||||
buildLangStrings,
|
||||
oldBuildLangPack,
|
||||
} from '../apiBuilders/misc';
|
||||
import { getApiChatIdFromMtpPeer } from '../apiBuilders/peers';
|
||||
import {
|
||||
buildApiPeerColors,
|
||||
buildApiPeerNotifySettings,
|
||||
buildApiPeerProfileColors,
|
||||
getApiChatIdFromMtpPeer,
|
||||
} from '../apiBuilders/peers';
|
||||
import {
|
||||
buildDisallowedGiftsSettings,
|
||||
buildInputChannel,
|
||||
|
||||
@ -49,12 +49,16 @@ import {
|
||||
buildMessageDraft,
|
||||
} from '../apiBuilders/messages';
|
||||
import {
|
||||
buildApiPeerNotifySettings,
|
||||
buildLangStrings,
|
||||
buildPrivacyKey,
|
||||
} from '../apiBuilders/misc';
|
||||
import { buildApiCurrencyAmount } from '../apiBuilders/payments';
|
||||
import { buildApiEmojiStatus, buildApiPeerId, getApiChatIdFromMtpPeer } from '../apiBuilders/peers';
|
||||
import {
|
||||
buildApiEmojiStatus,
|
||||
buildApiPeerId,
|
||||
buildApiPeerNotifySettings,
|
||||
getApiChatIdFromMtpPeer,
|
||||
} from '../apiBuilders/peers';
|
||||
import {
|
||||
buildApiPaidReactionPrivacy,
|
||||
buildApiReaction,
|
||||
|
||||
@ -2,9 +2,17 @@ import type { ApiBotCommand } from './bots';
|
||||
import type {
|
||||
ApiChatReactions, ApiFormattedText, ApiInputMessageReplyInfo, ApiInputSuggestedPostInfo, ApiPhoto, ApiStickerSet,
|
||||
} from './messages';
|
||||
import type { ApiBotVerification, ApiChatInviteImporter, ApiPeerNotifySettings, ApiRestrictionReason } from './misc';
|
||||
import type { ApiChatInviteImporter, ApiPeerNotifySettings, ApiRestrictionReason } from './misc';
|
||||
import type {
|
||||
ApiEmojiStatusType, ApiFakeType, ApiUser, ApiUsername,
|
||||
ApiBotVerification,
|
||||
ApiEmojiStatusType,
|
||||
ApiFakeType,
|
||||
ApiPeerColor,
|
||||
ApiProfileTab,
|
||||
ApiSendAsPeerId,
|
||||
} from './peers';
|
||||
import type {
|
||||
ApiUser, ApiUsername,
|
||||
} from './users';
|
||||
|
||||
type ApiChatType = (
|
||||
@ -156,6 +164,7 @@ export interface ApiChatFullInfo {
|
||||
boostsApplied?: number;
|
||||
boostsToUnrestrict?: number;
|
||||
botVerification?: ApiBotVerification;
|
||||
mainTab?: ApiProfileTab;
|
||||
}
|
||||
|
||||
export interface ApiChatMember {
|
||||
@ -235,23 +244,6 @@ export interface ApiChatFolder {
|
||||
hasMyInvites?: true;
|
||||
}
|
||||
|
||||
export interface ApiPeerSettings {
|
||||
isAutoArchived?: boolean;
|
||||
canReportSpam?: boolean;
|
||||
canAddContact?: boolean;
|
||||
canBlockContact?: boolean;
|
||||
chargedPaidMessageStars?: number;
|
||||
registrationMonth?: string;
|
||||
phoneCountry?: string;
|
||||
nameChangeDate?: number;
|
||||
photoChangeDate?: number;
|
||||
}
|
||||
|
||||
export interface ApiSendAsPeerId {
|
||||
id: string;
|
||||
isPremium?: boolean;
|
||||
}
|
||||
|
||||
export interface ApiTopic {
|
||||
id: number;
|
||||
isClosed?: boolean;
|
||||
@ -296,11 +288,6 @@ export interface ApiChatlistExportedInvite {
|
||||
peerIds: string[];
|
||||
}
|
||||
|
||||
export interface ApiPeerColor {
|
||||
color?: number;
|
||||
backgroundEmojiId?: string;
|
||||
}
|
||||
|
||||
export interface ApiMissingInvitedUser {
|
||||
id: string;
|
||||
isRequiringPremiumToInvite?: boolean;
|
||||
|
||||
@ -12,3 +12,4 @@ export * from './statistics';
|
||||
export * from './stories';
|
||||
export * from './business';
|
||||
export * from './stars';
|
||||
export * from './peers';
|
||||
|
||||
@ -4,12 +4,12 @@ import type {
|
||||
ApiBotInlineResult,
|
||||
ApiWebDocument,
|
||||
} from './bots';
|
||||
import type { ApiPeerColor } from './chats';
|
||||
import type { ApiMessageAction } from './messageActions';
|
||||
import type { ApiRestrictionReason } from './misc';
|
||||
import type {
|
||||
ApiLabeledPrice,
|
||||
} from './payments';
|
||||
import type { ApiPeerColor } from './peers';
|
||||
import type { ApiStarGiftUnique, ApiTypeCurrencyAmount } from './stars';
|
||||
import type {
|
||||
ApiMessageStoryData, ApiStory, ApiWebPageStickerData, ApiWebPageStoryData,
|
||||
@ -957,7 +957,8 @@ export type ApiTranscription = {
|
||||
transcriptionId: string;
|
||||
};
|
||||
|
||||
export type ApiMessageSearchType = 'text' | 'media' | 'documents' | 'links' | 'audio' | 'voice' | 'profilePhoto';
|
||||
export type ApiMessageSearchType = 'text' | 'media' | 'documents' | 'links' | 'audio' | 'voice' | 'gif'
|
||||
| 'profilePhoto';
|
||||
export type ApiGlobalMessageSearchType = 'text' |
|
||||
'channels' | 'media' | 'documents' | 'links' | 'audio' | 'voice' | 'publicPosts';
|
||||
export type ApiMessageSearchContext = 'all' | 'users' | 'groups' | 'channels';
|
||||
|
||||
@ -5,6 +5,7 @@ import type { IconName } from '../../types/icons';
|
||||
import type { RegularLangFnParameters } from '../../util/localization';
|
||||
import type { ApiDocument, ApiPhoto, ApiReaction } from './messages';
|
||||
import type { ApiPremiumSection } from './payments';
|
||||
import type { ApiBotVerification } from './peers';
|
||||
import type { ApiStarsSubscriptionPricing } from './stars';
|
||||
import type { ApiUser } from './users';
|
||||
|
||||
@ -287,26 +288,6 @@ export interface ApiConfig {
|
||||
maxForwardedCount: number;
|
||||
}
|
||||
|
||||
export type ApiPeerColorSet = string[];
|
||||
export type ApiPeerProfileColorSet = {
|
||||
paletteColors: string[];
|
||||
bgColors: string[];
|
||||
storyColors: string[];
|
||||
};
|
||||
|
||||
export type ApiPeerColorOption<T extends ApiPeerColorSet | ApiPeerProfileColorSet> = {
|
||||
isHidden?: true;
|
||||
colors?: T;
|
||||
darkColors?: T;
|
||||
};
|
||||
|
||||
export interface ApiPeerColors {
|
||||
general: Record<number, ApiPeerColorOption<ApiPeerColorSet>>;
|
||||
generalHash?: number;
|
||||
profile: Record<number, ApiPeerColorOption<ApiPeerProfileColorSet>>;
|
||||
profileHash?: number;
|
||||
}
|
||||
|
||||
export interface ApiTimezone {
|
||||
id: string;
|
||||
name: string;
|
||||
@ -352,21 +333,6 @@ export interface ApiCollectibleInfo {
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface ApiPeerPhotos {
|
||||
fallbackPhoto?: ApiPhoto;
|
||||
personalPhoto?: ApiPhoto;
|
||||
photos: ApiPhoto[];
|
||||
count: number;
|
||||
nextOffset?: number;
|
||||
isLoading?: boolean;
|
||||
}
|
||||
|
||||
export interface ApiBotVerification {
|
||||
botId: string;
|
||||
iconId: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export type ApiLimitType =
|
||||
| 'uploadMaxFileparts'
|
||||
| 'stickersFaved'
|
||||
|
||||
84
src/api/types/peers.ts
Normal file
84
src/api/types/peers.ts
Normal file
@ -0,0 +1,84 @@
|
||||
import type { ApiPhoto } from './messages';
|
||||
|
||||
export interface ApiPeerPhotos {
|
||||
fallbackPhoto?: ApiPhoto;
|
||||
personalPhoto?: ApiPhoto;
|
||||
photos: ApiPhoto[];
|
||||
count: number;
|
||||
nextOffset?: number;
|
||||
isLoading?: boolean;
|
||||
}
|
||||
|
||||
export type ApiFakeType = 'fake' | 'scam';
|
||||
|
||||
export interface ApiBotVerification {
|
||||
botId: string;
|
||||
iconId: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export type ApiEmojiStatusType = ApiEmojiStatus | ApiEmojiStatusCollectible;
|
||||
|
||||
export interface ApiEmojiStatus {
|
||||
type: 'regular';
|
||||
documentId: string;
|
||||
until?: number;
|
||||
}
|
||||
|
||||
export interface ApiEmojiStatusCollectible {
|
||||
type: 'collectible';
|
||||
collectibleId: string;
|
||||
documentId: string;
|
||||
title: string;
|
||||
slug: string;
|
||||
patternDocumentId: string;
|
||||
centerColor: string;
|
||||
edgeColor: string;
|
||||
patternColor: string;
|
||||
textColor: string;
|
||||
until?: number;
|
||||
}
|
||||
|
||||
export interface ApiPeerSettings {
|
||||
isAutoArchived?: boolean;
|
||||
canReportSpam?: boolean;
|
||||
canAddContact?: boolean;
|
||||
canBlockContact?: boolean;
|
||||
chargedPaidMessageStars?: number;
|
||||
registrationMonth?: string;
|
||||
phoneCountry?: string;
|
||||
nameChangeDate?: number;
|
||||
photoChangeDate?: number;
|
||||
}
|
||||
|
||||
export interface ApiSendAsPeerId {
|
||||
id: string;
|
||||
isPremium?: boolean;
|
||||
}
|
||||
|
||||
export interface ApiPeerColor {
|
||||
color?: number;
|
||||
backgroundEmojiId?: string;
|
||||
}
|
||||
|
||||
export type ApiPeerColorSet = string[];
|
||||
export type ApiPeerProfileColorSet = {
|
||||
paletteColors: string[];
|
||||
bgColors: string[];
|
||||
storyColors: string[];
|
||||
};
|
||||
|
||||
export type ApiPeerColorOption<T extends ApiPeerColorSet | ApiPeerProfileColorSet> = {
|
||||
isHidden?: true;
|
||||
colors?: T;
|
||||
darkColors?: T;
|
||||
};
|
||||
|
||||
export interface ApiPeerColors {
|
||||
general: Record<number, ApiPeerColorOption<ApiPeerColorSet>>;
|
||||
generalHash?: number;
|
||||
profile: Record<number, ApiPeerColorOption<ApiPeerProfileColorSet>>;
|
||||
profileHash?: number;
|
||||
}
|
||||
|
||||
export type ApiProfileTab = 'stories' | 'gifts' | 'media' | 'documents' | 'audio' | 'voice' | 'links' | 'gif';
|
||||
@ -18,7 +18,6 @@ import type {
|
||||
ApiChatFullInfo,
|
||||
ApiChatMember,
|
||||
ApiDraft,
|
||||
ApiPeerSettings,
|
||||
ApiTypingStatus,
|
||||
} from './chats';
|
||||
import type {
|
||||
@ -43,11 +42,12 @@ import type {
|
||||
ApiPeerNotifySettings,
|
||||
ApiSessionData,
|
||||
} from './misc';
|
||||
import type { ApiEmojiStatusType, ApiPeerSettings } from './peers';
|
||||
import type { ApiPrivacyKey, LangPackStringValue, PrivacyVisibility } from './settings';
|
||||
import type { ApiTypeCurrencyAmount } from './stars';
|
||||
import type { ApiStealthMode, ApiStory, ApiStorySkipped } from './stories';
|
||||
import type {
|
||||
ApiEmojiStatusType, ApiUser, ApiUserFullInfo, ApiUserStatus,
|
||||
ApiUser, ApiUserFullInfo, ApiUserStatus,
|
||||
} from './users';
|
||||
|
||||
export type ApiUpdateReady = {
|
||||
|
||||
@ -1,9 +1,15 @@
|
||||
import type { API_CHAT_TYPES } from '../../config';
|
||||
import type { ApiBotInfo } from './bots';
|
||||
import type { ApiBusinessIntro, ApiBusinessLocation, ApiBusinessWorkHours } from './business';
|
||||
import type { ApiPeerColor, ApiPeerSettings } from './chats';
|
||||
import type { ApiDocument, ApiPhoto } from './messages';
|
||||
import type { ApiBotVerification } from './misc';
|
||||
import type {
|
||||
ApiBotVerification,
|
||||
ApiEmojiStatusType,
|
||||
ApiFakeType,
|
||||
ApiPeerColor,
|
||||
ApiPeerSettings,
|
||||
ApiProfileTab,
|
||||
} from './peers';
|
||||
import type { ApiSavedStarGift, ApiStarsRating } from './stars';
|
||||
|
||||
export interface ApiUser {
|
||||
@ -75,10 +81,9 @@ export interface ApiUserFullInfo {
|
||||
botVerification?: ApiBotVerification;
|
||||
paidMessagesStars?: number;
|
||||
settings?: ApiPeerSettings;
|
||||
mainTab?: ApiProfileTab;
|
||||
}
|
||||
|
||||
export type ApiFakeType = 'fake' | 'scam';
|
||||
|
||||
export type ApiUserType = 'userTypeBot' | 'userTypeRegular' | 'userTypeDeleted' | 'userTypeUnknown';
|
||||
|
||||
export interface ApiUserStatus {
|
||||
@ -136,28 +141,6 @@ export interface ApiAttachBotIcon {
|
||||
document: ApiDocument;
|
||||
}
|
||||
|
||||
export type ApiEmojiStatusType = ApiEmojiStatus | ApiEmojiStatusCollectible;
|
||||
|
||||
export interface ApiEmojiStatus {
|
||||
type: 'regular';
|
||||
documentId: string;
|
||||
until?: number;
|
||||
}
|
||||
|
||||
export interface ApiEmojiStatusCollectible {
|
||||
type: 'collectible';
|
||||
collectibleId: string;
|
||||
documentId: string;
|
||||
title: string;
|
||||
slug: string;
|
||||
patternDocumentId: string;
|
||||
centerColor: string;
|
||||
edgeColor: string;
|
||||
patternColor: string;
|
||||
textColor: string;
|
||||
until?: number;
|
||||
}
|
||||
|
||||
export interface ApiBirthday {
|
||||
day: number;
|
||||
month: number;
|
||||
|
||||
@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="44" height="32"><path d="M15.33 15.009a7.105 7.105 0 1 1 .001-14.21 7.105 7.105 0 0 1-.001 14.21zM1.122 27.236c0-1.363.339-2.725 1.306-3.686 1.817-1.804 5.722-4.482 12.901-4.482s11.085 2.678 12.901 4.482c.967.96 1.306 2.322 1.306 3.686a4.011 4.011 0 0 1-3.984 4.01H5.13a4.011 4.011 0 0 1-4.011-4.01zm30.601 4.01a7.346 7.346 0 0 0 1.184-4.01c0-1.839-.45-4.238-2.302-6.076l-.042-.041c.326-.013.66-.02 1.004-.02 6.145 0 9.493 2.226 11.052 3.729.83.8 1.126 1.952 1.126 3.105a3.314 3.314 0 0 1-3.314 3.314h-8.708zm-.156-14.207a6.089 6.089 0 1 1 0-12.178 6.089 6.089 0 0 1 0 12.178z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><path d="M11.002 15.286a5 5 0 1 1 0-10 5 5 0 0 1 0 10m-10 8.606c0-.96.239-1.918.92-2.595C3.2 20.027 5.947 18.143 11 18.143c5.052 0 7.802 1.885 9.08 3.154.68.676.919 1.635.919 2.595a2.823 2.823 0 0 1-2.804 2.822H3.823A2.823 2.823 0 0 1 1 23.892zm21.537 2.822a5.17 5.17 0 0 0 .833-2.822c0-1.295-.316-2.983-1.62-4.277l-.03-.028q.345-.015.707-.015c4.325 0 6.681 1.567 7.779 2.625.584.563.792 1.374.792 2.185a2.33 2.33 0 0 1-2.332 2.333zm-.11-9.999a4.285 4.285 0 1 1 0-8.57 4.285 4.285 0 0 1 0 8.57" /></svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 632 B After Width: | Height: | Size: 567 B |
@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="none"><path fill="#000" d="M0 15C0 6.716 6.716 0 15 0c8.284 0 15 6.716 15 15 0 8.284-6.716 15-15 15-8.284 0-15-6.716-15-15Zm13.636-6.818a1.364 1.364 0 1 0 0 2.727h.682c.377 0 .682.305.682.682v8.864a1.364 1.364 0 1 0 2.727 0V11.59a3.41 3.41 0 0 0-3.409-3.41z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="none"><path fill="#000" d="M1 16C1 7.716 7.716 1 16 1s15 6.716 15 15-6.716 15-15 15S1 24.284 1 16m13.636-6.818a1.364 1.364 0 1 0 0 2.727h.682c.377 0 .682.305.682.682v8.864a1.364 1.364 0 1 0 2.727 0V12.59a3.41 3.41 0 0 0-3.409-3.41Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 335 B After Width: | Height: | Size: 309 B |
@ -1434,6 +1434,8 @@
|
||||
"ProfileBirthdayValueYear" = "{date} ({age} years old)";
|
||||
"ProfileBirthdayTodayValue" = "🎂 {date}";
|
||||
"ProfileBirthdayTodayValueYear" = "🎂 {date} ({age} years old)";
|
||||
"ProfileMenuSetMainTab" = "Set as Main Tab";
|
||||
"ProfileItemSubscribers" = "Subscribers";
|
||||
"MonetizationInfoTONTitle" = "What is 💎 TON?";
|
||||
"ChannelEarnLearnCoinAbout" = "TON is a blockchain platform and cryptocurrency that Telegram uses for its high speed and low commissions on transactions. {link}";
|
||||
"MonetizationBalanceZeroInfo" = "You will be able to collect rewards using Fragment, a third-party platform used by advertisers to pay for ads. {link}";
|
||||
@ -1710,6 +1712,7 @@
|
||||
"ProfileTabLinks" = "Links";
|
||||
"ProfileTabMusic" = "Music";
|
||||
"ProfileTabVoice" = "Voice";
|
||||
"ProfileTabGifs" = "GIF";
|
||||
"ProfileTabSharedGroups" = "Groups";
|
||||
"ProfileTabSimilarChannels" = "Similar Channels";
|
||||
"ProfileTabSimilarBots" = "Similar Bots";
|
||||
|
||||
@ -3,6 +3,7 @@ import { memo, useEffect, useRef, useState } from '../../lib/teact/teact';
|
||||
import type { ApiSticker } from '../../api/types';
|
||||
import type { AnimationLevel } from '../../types';
|
||||
|
||||
import { ANIMATION_LEVEL_MIN } from '../../config';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
|
||||
import useHorizontalScroll from '../../hooks/useHorizontalScroll';
|
||||
@ -38,7 +39,7 @@ const AnimatedTabList = ({
|
||||
const clipPathContainerRef = useRef<HTMLDivElement>();
|
||||
const selectedIndex = items.findIndex((item) => item.id === selectedItemId) || 0;
|
||||
const [clipPath, setClipPath] = useState<string>('');
|
||||
const shouldAnimate = animationLevel > 0;
|
||||
const shouldAnimate = animationLevel > ANIMATION_LEVEL_MIN;
|
||||
|
||||
useHorizontalScroll(containerRef, !items.length, true);
|
||||
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import type { FC } from '../../lib/teact/teact';
|
||||
import { memo, useRef } from '../../lib/teact/teact';
|
||||
|
||||
import type { ApiMessage } from '../../api/types';
|
||||
@ -8,7 +7,9 @@ import {
|
||||
getMessageHtmlId,
|
||||
getMessageIsSpoiler,
|
||||
getMessageVideo,
|
||||
getVideoMediaHash,
|
||||
} from '../../global/helpers';
|
||||
import { IS_TOUCH_ENV } from '../../util/browser/windowEnvironment';
|
||||
import buildClassName from '../../util/buildClassName';
|
||||
import { formatMediaDuration } from '../../util/dates/dateFormat';
|
||||
import stopEvent from '../../util/stopEvent';
|
||||
@ -21,6 +22,7 @@ import useLastCallback from '../../hooks/useLastCallback';
|
||||
import useMedia from '../../hooks/useMedia';
|
||||
import useMediaTransitionDeprecated from '../../hooks/useMediaTransitionDeprecated';
|
||||
|
||||
import OptimizedVideo from '../ui/OptimizedVideo';
|
||||
import MediaSpoiler from './MediaSpoiler';
|
||||
|
||||
import './Media.scss';
|
||||
@ -29,26 +31,32 @@ type OwnProps = {
|
||||
message: ApiMessage;
|
||||
idPrefix?: string;
|
||||
isProtected?: boolean;
|
||||
canAutoPlay?: boolean;
|
||||
observeIntersection?: ObserveFn;
|
||||
onClick?: (messageId: number, chatId: string) => void;
|
||||
};
|
||||
|
||||
const Media: FC<OwnProps> = ({
|
||||
const Media = ({
|
||||
message,
|
||||
idPrefix = 'shared-media',
|
||||
isProtected,
|
||||
canAutoPlay,
|
||||
observeIntersection,
|
||||
onClick,
|
||||
}) => {
|
||||
}: OwnProps) => {
|
||||
const ref = useRef<HTMLDivElement>();
|
||||
|
||||
const isIntersecting = useIsIntersecting(ref, observeIntersection);
|
||||
const [isHovering, markMouseOver, markMouseOut] = useFlag();
|
||||
|
||||
const thumbDataUri = useThumbnail(message);
|
||||
const mediaHash = useMessageMediaHash(message, 'pictogram');
|
||||
const mediaBlobUrl = useMedia(mediaHash, !isIntersecting);
|
||||
const transitionClassNames = useMediaTransitionDeprecated(mediaBlobUrl);
|
||||
|
||||
const video = getMessageVideo(message);
|
||||
const fullGiftHash = video?.isGif ? getVideoMediaHash(video, 'full') : undefined;
|
||||
const fullGifBlobUrl = useMedia(fullGiftHash, !isIntersecting);
|
||||
|
||||
const hasSpoiler = getMessageIsSpoiler(message);
|
||||
const [isSpoilerShown, , hideSpoiler] = useFlag(hasSpoiler);
|
||||
@ -64,6 +72,8 @@ const Media: FC<OwnProps> = ({
|
||||
id={`${idPrefix}${getMessageHtmlId(message.id)}`}
|
||||
className="Media scroll-item"
|
||||
onClick={onClick ? handleClick : undefined}
|
||||
onMouseOver={!IS_TOUCH_ENV ? markMouseOver : undefined}
|
||||
onMouseOut={!IS_TOUCH_ENV ? markMouseOut : undefined}
|
||||
>
|
||||
<img
|
||||
src={thumbDataUri}
|
||||
@ -73,14 +83,28 @@ const Media: FC<OwnProps> = ({
|
||||
decoding="async"
|
||||
onContextMenu={isProtected ? stopEvent : undefined}
|
||||
/>
|
||||
<img
|
||||
src={mediaBlobUrl}
|
||||
className={buildClassName('full-media', 'media-miniature', transitionClassNames)}
|
||||
alt=""
|
||||
draggable={!isProtected}
|
||||
decoding="async"
|
||||
onContextMenu={isProtected ? stopEvent : undefined}
|
||||
/>
|
||||
{fullGifBlobUrl ? (
|
||||
<OptimizedVideo
|
||||
canPlay={isIntersecting && !hasSpoiler && isHovering && Boolean(canAutoPlay)}
|
||||
src={fullGifBlobUrl}
|
||||
className={buildClassName('full-media', 'media-miniature', transitionClassNames)}
|
||||
muted
|
||||
loop
|
||||
playsInline
|
||||
draggable={false}
|
||||
disablePictureInPicture
|
||||
onContextMenu={isProtected ? stopEvent : undefined}
|
||||
/>
|
||||
) : (
|
||||
<img
|
||||
src={mediaBlobUrl}
|
||||
className={buildClassName('full-media', 'media-miniature', transitionClassNames)}
|
||||
alt=""
|
||||
draggable={false}
|
||||
decoding="async"
|
||||
onContextMenu={isProtected ? stopEvent : undefined}
|
||||
/>
|
||||
)}
|
||||
{hasSpoiler && (
|
||||
<MediaSpoiler
|
||||
thumbDataUri={mediaBlobUrl || thumbDataUri}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import type { FC } from '../../../lib/teact/teact';
|
||||
import {
|
||||
memo, useMemo,
|
||||
} from '../../../lib/teact/teact';
|
||||
@ -12,8 +11,8 @@ import type {
|
||||
ApiUserFullInfo,
|
||||
ApiUsername,
|
||||
} from '../../../api/types';
|
||||
import type { BotAppPermissions } from '../../../types';
|
||||
import { MAIN_THREAD_ID } from '../../../api/types';
|
||||
import { type BotAppPermissions, ManagementScreens } from '../../../types';
|
||||
|
||||
import {
|
||||
FRAGMENT_PHONE_CODE, FRAGMENT_PHONE_LENGTH, MUTE_INDEFINITE_TIMESTAMP, UNMUTE_TIMESTAMP,
|
||||
@ -22,6 +21,7 @@ import {
|
||||
buildStaticMapHash,
|
||||
getChatLink,
|
||||
getHasAdminRight,
|
||||
isChatAdmin,
|
||||
isChatChannel,
|
||||
isUserRightBanned,
|
||||
} from '../../../global/helpers';
|
||||
@ -92,6 +92,7 @@ type StateProps = {
|
||||
isBotCanManageEmojiStatus?: boolean;
|
||||
botAppPermissions?: BotAppPermissions;
|
||||
botVerification?: ApiBotVerification;
|
||||
canViewSubscribers?: boolean;
|
||||
};
|
||||
|
||||
const DEFAULT_MAP_CONFIG = {
|
||||
@ -102,7 +103,7 @@ const DEFAULT_MAP_CONFIG = {
|
||||
|
||||
const BOT_VERIFICATION_ICON_SIZE = 16;
|
||||
|
||||
const ChatExtra: FC<OwnProps & StateProps> = ({
|
||||
const ChatExtra = ({
|
||||
chatOrUserId,
|
||||
user,
|
||||
chat,
|
||||
@ -124,7 +125,8 @@ const ChatExtra: FC<OwnProps & StateProps> = ({
|
||||
className,
|
||||
style,
|
||||
isInSettings,
|
||||
}) => {
|
||||
canViewSubscribers,
|
||||
}: OwnProps & StateProps) => {
|
||||
const {
|
||||
showNotification,
|
||||
updateChatMutedState,
|
||||
@ -136,6 +138,7 @@ const ChatExtra: FC<OwnProps & StateProps> = ({
|
||||
requestMainWebView,
|
||||
toggleUserEmojiStatusPermission,
|
||||
toggleUserLocationPermission,
|
||||
requestNextManagementScreen,
|
||||
} = getActions();
|
||||
|
||||
const {
|
||||
@ -261,6 +264,10 @@ const ChatExtra: FC<OwnProps & StateProps> = ({
|
||||
copy(formatUsername(username.username, isChat), oldLang(isChat ? 'Link' : 'Username'));
|
||||
});
|
||||
|
||||
const handleOpenSubscribers = useLastCallback(() => {
|
||||
requestNextManagementScreen({ screen: ManagementScreens.ChannelSubscribers });
|
||||
});
|
||||
|
||||
const handleOpenApp = useLastCallback(() => {
|
||||
const botId = user?.id;
|
||||
if (!botId) {
|
||||
@ -476,6 +483,12 @@ const ChatExtra: FC<OwnProps & StateProps> = ({
|
||||
/>
|
||||
</ListItem>
|
||||
)}
|
||||
{canViewSubscribers && (
|
||||
<ListItem icon="group" narrow multiline ripple onClick={handleOpenSubscribers}>
|
||||
<div className="title">{lang('ProfileItemSubscribers')}</div>
|
||||
<span className="subtitle">{lang.number(chat?.membersCount || 0)}</span>
|
||||
</ListItem>
|
||||
)}
|
||||
{botVerification && (
|
||||
<div className={styles.botVerificationSection}>
|
||||
<CustomEmoji
|
||||
@ -510,6 +523,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
const chatInviteLink = chatFullInfo?.inviteLink;
|
||||
const description = userFullInfo?.bio || chatFullInfo?.about;
|
||||
|
||||
const canViewSubscribers = chat && isChatChannel(chat) && isChatAdmin(chat);
|
||||
const canInviteUsers = chat && !user && (
|
||||
(!isChatChannel(chat) && !isUserRightBanned(chat, 'inviteUsers'))
|
||||
|| getHasAdminRight(chat, 'inviteUsers')
|
||||
@ -542,6 +556,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
hasMainMiniApp,
|
||||
isBotCanManageEmojiStatus: userFullInfo?.isBotCanManageEmojiStatus,
|
||||
botVerification,
|
||||
canViewSubscribers,
|
||||
};
|
||||
},
|
||||
)(ChatExtra));
|
||||
|
||||
@ -18,7 +18,8 @@ import { type MediaViewerMedia, MediaViewerOrigin, type ThreadId } from '../../t
|
||||
import { ANIMATION_END_DELAY } from '../../config';
|
||||
import { requestMutation } from '../../lib/fasterdom/fasterdom';
|
||||
import {
|
||||
getChatMediaMessageIds, getMessagePaidMedia, isChatAdmin,
|
||||
getMessageContentIds,
|
||||
getMessagePaidMedia, isChatAdmin,
|
||||
} from '../../global/helpers';
|
||||
import {
|
||||
selectChatMessage,
|
||||
@ -156,7 +157,7 @@ const MediaViewer = ({
|
||||
bestData,
|
||||
dimensions,
|
||||
isGif,
|
||||
isFromSharedMedia,
|
||||
contentType,
|
||||
} = useMediaProps({
|
||||
media, isAvatar: Boolean(avatarOwner), origin, delay: isGhostAnimation && ANIMATION_DURATION,
|
||||
});
|
||||
@ -173,8 +174,8 @@ const MediaViewer = ({
|
||||
const messageMediaIds = useMemo(() => {
|
||||
return withDynamicLoading
|
||||
? collectedMessageIds
|
||||
: getChatMediaMessageIds(chatMessages || {}, collectedMessageIds || [], isFromSharedMedia);
|
||||
}, [chatMessages, collectedMessageIds, isFromSharedMedia, withDynamicLoading]);
|
||||
: getMessageContentIds(chatMessages || {}, collectedMessageIds || [], contentType);
|
||||
}, [chatMessages, collectedMessageIds, contentType, withDynamicLoading]);
|
||||
|
||||
if (isOpen && (!prevSenderId || prevSenderId !== senderId || animationKey.current === undefined)) {
|
||||
animationKey.current = isSingle ? 0 : (messageId || mediaIndex);
|
||||
@ -520,7 +521,7 @@ export default memo(withGlobal(
|
||||
const currentItem = getMediaViewerItem({
|
||||
avatarOwner, standaloneMedia, profilePhotos, mediaIndex,
|
||||
});
|
||||
const viewableMedia = selectViewableMedia(global, currentItem);
|
||||
const viewableMedia = selectViewableMedia(global, origin, currentItem);
|
||||
|
||||
return {
|
||||
profilePhotos,
|
||||
@ -565,6 +566,11 @@ export default memo(withGlobal(
|
||||
}
|
||||
}
|
||||
|
||||
const currentItem = getMediaViewerItem({
|
||||
message, standaloneMedia, mediaIndex, sponsoredMessage,
|
||||
});
|
||||
const viewableMedia = selectViewableMedia(global, origin, currentItem);
|
||||
|
||||
let chatMessages: Record<number, ApiMessage> | undefined;
|
||||
|
||||
if (chatId) {
|
||||
@ -588,7 +594,8 @@ export default memo(withGlobal(
|
||||
collectedMessageIds = foundIds;
|
||||
} else if (origin === MediaViewerOrigin.SharedMedia) {
|
||||
const currentSearch = selectCurrentSharedMediaSearch(global);
|
||||
const { foundIds } = (currentSearch && currentSearch.resultsByType && currentSearch.resultsByType.media) || {};
|
||||
const resultsByType = currentSearch?.resultsByType;
|
||||
const { foundIds } = (viewableMedia?.isGif ? resultsByType?.gif : resultsByType?.media) || {};
|
||||
collectedMessageIds = foundIds;
|
||||
} else if (isOriginInline || isOriginAlbum) {
|
||||
const outlyingList = selectOutlyingListByMessageId(global, chatId, threadId, messageId);
|
||||
@ -596,11 +603,6 @@ export default memo(withGlobal(
|
||||
}
|
||||
}
|
||||
|
||||
const currentItem = getMediaViewerItem({
|
||||
message, standaloneMedia, mediaIndex, sponsoredMessage,
|
||||
});
|
||||
const viewableMedia = selectViewableMedia(global, currentItem);
|
||||
|
||||
return {
|
||||
chatId,
|
||||
threadId,
|
||||
|
||||
@ -413,7 +413,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
const canDelete = canDeleteMessage || canDeleteAvatar;
|
||||
const canUpdate = canUpdateMedia && Boolean(avatarPhoto) && !isCurrentAvatar;
|
||||
const messageListType = currentMessageList?.type;
|
||||
const viewableMedia = selectViewableMedia(global, item);
|
||||
const viewableMedia = selectViewableMedia(global, origin, item);
|
||||
|
||||
return {
|
||||
activeDownloads,
|
||||
|
||||
@ -257,7 +257,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
const message = item.type === 'message' ? item.message : undefined;
|
||||
const sponsoredMessage = item.type === 'sponsoredMessage' ? item.message : undefined;
|
||||
const textMessage = message || sponsoredMessage;
|
||||
const viewableMedia = selectViewableMedia(global, item);
|
||||
const viewableMedia = selectViewableMedia(global, origin, item);
|
||||
|
||||
const maxTimestamp = message && selectMessageTimestampableDuration(global, message, true);
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@ import type {
|
||||
ApiMessage, ApiPeer, ApiPeerPhotos, ApiSponsoredMessage,
|
||||
} from '../../../api/types';
|
||||
import type { GlobalState } from '../../../global/types';
|
||||
import type { MediaViewerMedia } from '../../../types';
|
||||
import { type MediaViewerMedia, MediaViewerOrigin } from '../../../types';
|
||||
|
||||
import { getMessageContent, isDocumentPhoto, isDocumentVideo } from '../../../global/helpers';
|
||||
import { selectWebPageFromMessage } from '../../../global/selectors';
|
||||
@ -28,6 +28,7 @@ export type MediaViewerItem = {
|
||||
|
||||
export type ViewableMedia = {
|
||||
media: MediaViewerMedia;
|
||||
isGif?: boolean;
|
||||
isSingle?: boolean;
|
||||
};
|
||||
|
||||
@ -77,12 +78,16 @@ export function getMediaViewerItem({
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export default function selectViewableMedia(global: GlobalState, params?: MediaViewerItem): ViewableMedia | undefined {
|
||||
export default function selectViewableMedia(
|
||||
global: GlobalState, origin?: MediaViewerOrigin, params?: MediaViewerItem,
|
||||
): ViewableMedia | undefined {
|
||||
if (!params) return undefined;
|
||||
|
||||
if (params.type === 'standalone') {
|
||||
const media = params.media[params.mediaIndex];
|
||||
return {
|
||||
media: params.media[params.mediaIndex],
|
||||
media,
|
||||
isGif: media.mediaType === 'video' && media.isGif,
|
||||
isSingle: params.media.length === 1,
|
||||
};
|
||||
}
|
||||
@ -134,6 +139,7 @@ export default function selectViewableMedia(global: GlobalState, params?: MediaV
|
||||
const { photo: extendedPhoto, video: extendedVideo } = extendedMedia;
|
||||
return {
|
||||
media: (extendedPhoto || extendedVideo)!,
|
||||
isGif: extendedVideo?.isGif,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -143,7 +149,8 @@ export default function selectViewableMedia(global: GlobalState, params?: MediaV
|
||||
if (media) {
|
||||
return {
|
||||
media,
|
||||
isSingle: video?.isGif,
|
||||
isGif: video?.isGif,
|
||||
isSingle: video?.isGif && origin !== MediaViewerOrigin.SharedMedia,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { useMemo } from '../../../lib/teact/teact';
|
||||
|
||||
import type { MediaViewerMedia } from '../../../types';
|
||||
import { ApiMediaFormat } from '../../../api/types';
|
||||
import { ApiMediaFormat, type ApiMessageSearchType } from '../../../api/types';
|
||||
import { MediaViewerOrigin } from '../../../types';
|
||||
|
||||
import {
|
||||
@ -46,6 +46,8 @@ export const useMediaProps = ({
|
||||
const isFromSharedMedia = origin === MediaViewerOrigin.SharedMedia;
|
||||
const isFromSearch = origin === MediaViewerOrigin.SearchResult;
|
||||
|
||||
const contentType: ApiMessageSearchType = isGif ? 'gif' : 'media';
|
||||
|
||||
const getMediaOrAvatarHash = useMemo(() => (isFull?: boolean) => {
|
||||
if (!media) return undefined;
|
||||
|
||||
@ -133,7 +135,7 @@ export const useMediaProps = ({
|
||||
bestImageData,
|
||||
bestData,
|
||||
dimensions,
|
||||
isFromSharedMedia,
|
||||
contentType,
|
||||
isVideoAvatar,
|
||||
isLocal,
|
||||
loadProgress,
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
@use '../../styles/mixins';
|
||||
|
||||
.Profile {
|
||||
scrollbar-gutter: stable;
|
||||
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
display: flex;
|
||||
@ -134,6 +136,7 @@
|
||||
&.storiesArchive-list,
|
||||
&.stories-list,
|
||||
&.media-list,
|
||||
&.gif-list,
|
||||
&.previewMedia-list,
|
||||
&.gifts-list {
|
||||
display: grid;
|
||||
|
||||
@ -6,6 +6,7 @@ import type {
|
||||
ApiChat,
|
||||
ApiChatMember,
|
||||
ApiMessage,
|
||||
ApiProfileTab,
|
||||
ApiSavedStarGift,
|
||||
ApiStarGiftCollection,
|
||||
ApiStoryAlbum,
|
||||
@ -29,7 +30,6 @@ import {
|
||||
getIsDownloading,
|
||||
getIsSavedDialog,
|
||||
getMessageDocument,
|
||||
isChatAdmin,
|
||||
isChatChannel,
|
||||
isChatGroup,
|
||||
isUserBot,
|
||||
@ -38,6 +38,7 @@ import {
|
||||
import { getSavedGiftKey } from '../../global/helpers/stars';
|
||||
import {
|
||||
selectActiveDownloads,
|
||||
selectCanUpdateMainTab,
|
||||
selectChat,
|
||||
selectChatFullInfo,
|
||||
selectChatMessages,
|
||||
@ -47,6 +48,7 @@ import {
|
||||
selectIsRightColumnShown,
|
||||
selectMonoforumChannel,
|
||||
selectPeerStories,
|
||||
selectPerformanceSettingsValue,
|
||||
selectSimilarBotsIds,
|
||||
selectSimilarChannelIds,
|
||||
selectTabState,
|
||||
@ -86,6 +88,7 @@ import useLang from '../../hooks/useLang';
|
||||
import useLastCallback from '../../hooks/useLastCallback';
|
||||
import useOldLang from '../../hooks/useOldLang';
|
||||
import useSyncEffect from '../../hooks/useSyncEffect';
|
||||
import useSyncEffectWithPrevDeps from '../../hooks/useSyncEffectWithPrevDeps.ts';
|
||||
import useAsyncRendering from './hooks/useAsyncRendering';
|
||||
import useProfileState from './hooks/useProfileState';
|
||||
import useProfileViewportIds from './hooks/useProfileViewportIds';
|
||||
@ -112,7 +115,7 @@ import InfiniteScroll from '../ui/InfiniteScroll';
|
||||
import Link from '../ui/Link';
|
||||
import ListItem, { type MenuItemContextAction } from '../ui/ListItem';
|
||||
import Spinner from '../ui/Spinner';
|
||||
import TabList from '../ui/TabList';
|
||||
import TabList, { type TabWithProperties } from '../ui/TabList';
|
||||
import Transition from '../ui/Transition';
|
||||
import DeleteMemberModal from './DeleteMemberModal';
|
||||
import StarGiftCollectionList from './gifts/StarGiftCollectionList';
|
||||
@ -179,24 +182,40 @@ type StateProps = {
|
||||
isSavedMessages?: boolean;
|
||||
isSynced?: boolean;
|
||||
hasAvatar?: boolean;
|
||||
mainTab?: ApiProfileTab;
|
||||
canUpdateMainTab?: boolean;
|
||||
canAutoPlayGifs?: boolean;
|
||||
};
|
||||
|
||||
type TabProps = {
|
||||
type LocalTabProps = {
|
||||
type: ProfileTabType;
|
||||
key: RegularLangKey;
|
||||
};
|
||||
|
||||
const TABS: TabProps[] = [
|
||||
type TabWithPropertiesAndType = TabWithProperties & {
|
||||
type: ProfileTabType;
|
||||
};
|
||||
|
||||
const TABS: LocalTabProps[] = [
|
||||
{ type: 'media', key: 'ProfileTabMedia' },
|
||||
{ type: 'documents', key: 'ProfileTabFiles' },
|
||||
{ type: 'links', key: 'ProfileTabLinks' },
|
||||
{ type: 'audio', key: 'ProfileTabMusic' },
|
||||
{ type: 'gif', key: 'ProfileTabGifs' },
|
||||
];
|
||||
|
||||
const HIDDEN_RENDER_DELAY = 1000;
|
||||
const INTERSECTION_THROTTLE = 500;
|
||||
|
||||
const SHARED_MEDIA_TYPES = new Set<string>(['media', 'documents', 'links', 'audio', 'voice']);
|
||||
const VALID_CHANNEL_MAIN_TAB_TYPES = new Set<StringAutocomplete<ApiProfileTab>>([
|
||||
'stories', 'gifts', 'media', 'documents', 'audio', 'voice', 'links', 'gif',
|
||||
]);
|
||||
const VALID_USER_MAIN_TAB_TYPES = new Set<StringAutocomplete<ApiProfileTab>>([
|
||||
'stories', 'gifts',
|
||||
]);
|
||||
const SHARED_MEDIA_TYPES = new Set<StringAutocomplete<SharedMediaType>>([
|
||||
'media', 'documents', 'links', 'audio', 'voice', 'gif',
|
||||
]);
|
||||
|
||||
const Profile = ({
|
||||
chatId,
|
||||
@ -252,6 +271,9 @@ const Profile = ({
|
||||
isSavedMessages,
|
||||
isSynced,
|
||||
hasAvatar,
|
||||
mainTab,
|
||||
canUpdateMainTab,
|
||||
canAutoPlayGifs,
|
||||
onProfileStateChange,
|
||||
}: OwnProps & StateProps) => {
|
||||
const {
|
||||
@ -276,11 +298,14 @@ const Profile = ({
|
||||
loadStoryAlbums,
|
||||
resetSelectedStoryAlbum,
|
||||
changeProfileTab,
|
||||
setMainProfileTab,
|
||||
} = getActions();
|
||||
|
||||
const containerRef = useRef<HTMLDivElement>();
|
||||
const transitionRef = useRef<HTMLDivElement>();
|
||||
|
||||
const shouldSkipTransitionRef = useRef(false);
|
||||
|
||||
const oldLang = useOldLang();
|
||||
const lang = useLang();
|
||||
|
||||
@ -296,8 +321,11 @@ const Profile = ({
|
||||
|
||||
const [restoreContentHeightKey, setRestoreContentHeightKey] = useState(0);
|
||||
|
||||
const isUser = isUserId(chatId);
|
||||
const validMainTabTypes = isUser ? VALID_USER_MAIN_TAB_TYPES : VALID_CHANNEL_MAIN_TAB_TYPES;
|
||||
|
||||
const tabs = useMemo(() => {
|
||||
const arr: TabProps[] = [];
|
||||
const arr: LocalTabProps[] = [];
|
||||
if (isGeneralSavedMessages) {
|
||||
arr.push({ type: 'dialogs', key: 'ProfileTabSavedDialogs' });
|
||||
}
|
||||
@ -306,16 +334,16 @@ const Profile = ({
|
||||
arr.push({ type: 'stories', key: 'ProfileTabStories' });
|
||||
}
|
||||
|
||||
if (hasStoriesTab && isOwnProfile) {
|
||||
arr.push({ type: 'storiesArchive', key: 'ProfileTabStoriesArchive' });
|
||||
}
|
||||
|
||||
if (hasGiftsTab) {
|
||||
arr.push({ type: 'gifts', key: 'ProfileTabGifts' });
|
||||
}
|
||||
|
||||
if (hasStoriesTab && isOwnProfile) {
|
||||
arr.push({ type: 'storiesArchive', key: 'ProfileTabStoriesArchive' });
|
||||
}
|
||||
|
||||
if (hasMembersTab && !isOwnProfile) {
|
||||
arr.push({ type: 'members', key: isChannel ? 'ProfileTabSubscribers' : 'ProfileTabMembers' });
|
||||
arr.push({ type: 'members', key: 'ProfileTabMembers' });
|
||||
}
|
||||
|
||||
if (hasPreviewMediaTab && !isOwnProfile) {
|
||||
@ -349,13 +377,35 @@ const Profile = ({
|
||||
arr.push(TABS[0]);
|
||||
}
|
||||
|
||||
return arr.map((tab) => ({
|
||||
type: tab.type,
|
||||
title: lang(tab.key),
|
||||
}));
|
||||
if (mainTab) {
|
||||
const mainTabIndex = arr.findIndex((tab) => tab.type === mainTab);
|
||||
if (mainTabIndex !== -1) {
|
||||
const newFirstTab = arr[mainTabIndex];
|
||||
arr.splice(mainTabIndex, 1);
|
||||
arr.unshift(newFirstTab);
|
||||
}
|
||||
}
|
||||
|
||||
return arr.map((tab) => {
|
||||
const contextActions: MenuItemContextAction[] | undefined = canUpdateMainTab && mainTab !== tab.type
|
||||
&& validMainTabTypes.has(tab.type) ? [{
|
||||
title: lang('ProfileMenuSetMainTab'),
|
||||
icon: 'replace',
|
||||
handler: () => {
|
||||
setMainProfileTab({ chatId, tab: tab.type as ApiProfileTab });
|
||||
},
|
||||
}] : undefined;
|
||||
|
||||
return {
|
||||
type: tab.type,
|
||||
title: lang(tab.key),
|
||||
contextActions,
|
||||
} satisfies TabWithPropertiesAndType;
|
||||
});
|
||||
}, [
|
||||
isGeneralSavedMessages, hasStoriesTab, hasGiftsTab, hasMembersTab, hasPreviewMediaTab, isTopicInfo,
|
||||
hasCommonChatsTab, isChannel, isBot, similarChannels?.length, similarBots?.length, lang, isOwnProfile,
|
||||
mainTab, chatId, canUpdateMainTab, validMainTabTypes,
|
||||
]);
|
||||
|
||||
const [allowAutoScrollToTabs, startAutoScrollToTabsIfNeeded, stopAutoScrollToTabs] = useFlag(false);
|
||||
@ -377,6 +427,11 @@ const Profile = ({
|
||||
setActiveTab(tabs[0].type); // Set default tab
|
||||
}, [isClosed, profileTab, tabs]);
|
||||
|
||||
useEffectWithPrevDeps(([prevMainTab]) => {
|
||||
if (prevMainTab || !mainTab) return;
|
||||
setActiveTab(mainTab); // Only focus when loading full info
|
||||
}, [mainTab]);
|
||||
|
||||
const handleSwitchTab = useCallback((index: number) => {
|
||||
startAutoScrollToTabsIfNeeded();
|
||||
setActiveTab(tabs[index].type);
|
||||
@ -430,6 +485,17 @@ const Profile = ({
|
||||
return index === -1 ? 0 : index;
|
||||
}, [profileTab, tabs]);
|
||||
|
||||
// Reset skip transition flag from previous render
|
||||
if (shouldSkipTransitionRef.current) {
|
||||
shouldSkipTransitionRef.current = false;
|
||||
}
|
||||
|
||||
useSyncEffectWithPrevDeps(([prevProfileTab, prevActiveTabIndex]) => {
|
||||
if (prevProfileTab === profileTab && prevActiveTabIndex !== activeTabIndex) {
|
||||
shouldSkipTransitionRef.current = true;
|
||||
}
|
||||
}, [profileTab, activeTabIndex]);
|
||||
|
||||
const tabType = tabs[activeTabIndex].type;
|
||||
const handleLoadCommonChats = useCallback(() => {
|
||||
loadCommonChats({ userId: chatId });
|
||||
@ -498,10 +564,7 @@ const Profile = ({
|
||||
|
||||
const shouldRenderProfileInfo = !noProfileInfo && !isSavedMessages;
|
||||
|
||||
const isFirstTab = (isGeneralSavedMessages && resultType === 'dialogs')
|
||||
|| (hasStoriesTab && resultType === 'stories')
|
||||
|| resultType === 'members'
|
||||
|| (!hasMembersTab && resultType === 'media');
|
||||
const isFirstTab = tabs[0].type === resultType;
|
||||
const activeKey = tabs.findIndex(({ type }) => type === resultType);
|
||||
|
||||
const [isGiftCollectionsShowed, markGiftCollectionsShowed, unmarkGiftCollectionsShowed] = useFlag(false);
|
||||
@ -561,7 +624,7 @@ const Profile = ({
|
||||
handleStopAutoScrollToTabs,
|
||||
});
|
||||
|
||||
const { applyTransitionFix, releaseTransitionFix } = useTransitionFixes(containerRef);
|
||||
useTransitionFixes(containerRef);
|
||||
|
||||
const [cacheBuster, resetCacheBuster] = useCacheBuster();
|
||||
|
||||
@ -570,11 +633,6 @@ const Profile = ({
|
||||
throttleMs: INTERSECTION_THROTTLE,
|
||||
});
|
||||
|
||||
const handleTransitionStop = useLastCallback(() => {
|
||||
releaseTransitionFix();
|
||||
resetCacheBuster();
|
||||
});
|
||||
|
||||
const handleNewMemberDialogOpen = useLastCallback(() => {
|
||||
setNewChatMembersDialogState({ newChatMembersProgress: NewChatMembersProgress.InProgress });
|
||||
});
|
||||
@ -613,16 +671,6 @@ const Profile = ({
|
||||
setDeletingUserId(undefined);
|
||||
});
|
||||
|
||||
useEffectWithPrevDeps(([prevHasMemberTabs]) => {
|
||||
if (prevHasMemberTabs === undefined || activeTabIndex === 0 || prevHasMemberTabs === hasMembersTab) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newActiveTab = Math.min(activeTabIndex + (hasMembersTab ? 1 : -1), tabs.length - 1);
|
||||
|
||||
setActiveTab(tabs[newActiveTab].type);
|
||||
}, [hasMembersTab, activeTabIndex, tabs]);
|
||||
|
||||
const handleResetGiftsFilter = useLastCallback(() => {
|
||||
resetGiftProfileFilter({ peerId: chatId });
|
||||
});
|
||||
@ -800,6 +848,9 @@ const Profile = ({
|
||||
case 'storiesArchive':
|
||||
text = oldLang('StoryList.ArchivedEmptyState.Title');
|
||||
break;
|
||||
case 'gif':
|
||||
text = oldLang('lng_media_gif_empty');
|
||||
break;
|
||||
default:
|
||||
text = oldLang('SharedMedia.EmptyTitle');
|
||||
}
|
||||
@ -825,15 +876,16 @@ const Profile = ({
|
||||
shouldShowContentPanel && 'showContentPanel',
|
||||
noTransition && 'noTransition',
|
||||
)}
|
||||
dir={oldLang.isRtl && resultType === 'media' ? 'rtl' : undefined}
|
||||
dir={lang.isRtl && (resultType === 'media' || resultType === 'gif') ? 'rtl' : undefined}
|
||||
teactFastList
|
||||
>
|
||||
{resultType === 'media' ? (
|
||||
{resultType === 'media' || resultType === 'gif' ? (
|
||||
(viewportIds as number[]).map((id) => messagesById[id] && (
|
||||
<Media
|
||||
key={id}
|
||||
message={messagesById[id]}
|
||||
isProtected={isChatProtected || messagesById[id].isProtected}
|
||||
canAutoPlay={canAutoPlayGifs}
|
||||
observeIntersection={observeIntersectionForMedia}
|
||||
onClick={handleSelectMedia}
|
||||
/>
|
||||
@ -988,17 +1040,10 @@ const Profile = ({
|
||||
|
||||
onClick={() => openChat({ id: userId })}
|
||||
>
|
||||
{isUserId(userId) ? (
|
||||
<PrivateChatInfo
|
||||
userId={userId}
|
||||
avatarSize="medium"
|
||||
/>
|
||||
) : (
|
||||
<GroupChatInfo
|
||||
chatId={userId}
|
||||
avatarSize="medium"
|
||||
/>
|
||||
)}
|
||||
<PrivateChatInfo
|
||||
userId={userId}
|
||||
avatarSize="medium"
|
||||
/>
|
||||
</ListItem>
|
||||
))}
|
||||
{!isCurrentUserPremium && (
|
||||
@ -1081,7 +1126,7 @@ const Profile = ({
|
||||
<Transition
|
||||
className={`${resultType}-list`}
|
||||
activeKey={contentTransitionKey}
|
||||
name={resolveTransitionName('slideOptimized', animationLevel, undefined, oldLang.isRtl)}
|
||||
name={resolveTransitionName('slideOptimized', animationLevel, undefined, lang.isRtl)}
|
||||
shouldCleanup
|
||||
shouldRestoreHeight
|
||||
restoreHeightKey={restoreContentHeightKey}
|
||||
@ -1149,13 +1194,13 @@ const Profile = ({
|
||||
>
|
||||
<Transition
|
||||
ref={transitionRef}
|
||||
name={resolveTransitionName('slideOptimized', animationLevel, undefined, oldLang.isRtl)}
|
||||
name={shouldSkipTransitionRef.current ? 'none'
|
||||
: resolveTransitionName('slideOptimized', animationLevel, undefined, lang.isRtl)}
|
||||
activeKey={activeKey}
|
||||
renderCount={tabs.length}
|
||||
shouldRestoreHeight
|
||||
className="shared-media-transition"
|
||||
onStart={applyTransitionFix}
|
||||
onStop={handleTransitionStop}
|
||||
onStop={resetCacheBuster}
|
||||
restoreHeightKey={shouldUseTransitionForContent ? restoreContentHeightKey : undefined}
|
||||
contentSelector={shouldUseTransitionForContent
|
||||
? '.Transition > .Transition_slide-active > .Transition > .Transition_slide-active > .content'
|
||||
@ -1218,8 +1263,7 @@ export default memo(withGlobal<OwnProps>(
|
||||
const isGroup = chat && isChatGroup(chat);
|
||||
const isChannel = chat && isChatChannel(chat);
|
||||
const isBot = user && isUserBot(user);
|
||||
const hasMembersTab = !isTopicInfo && !isSavedDialog
|
||||
&& (isGroup || (isChannel && isChatAdmin(chat))) && !chat?.isMonoforum;
|
||||
const hasMembersTab = !isTopicInfo && !isSavedDialog && isGroup && !chat?.isMonoforum;
|
||||
const members = chatFullInfo?.members;
|
||||
const adminMembersById = chatFullInfo?.adminMembersById;
|
||||
const areMembersHidden = hasMembersTab && chat
|
||||
@ -1265,6 +1309,8 @@ export default memo(withGlobal<OwnProps>(
|
||||
const isRestricted = chat && selectIsChatRestricted(global, chat.id);
|
||||
const hasAvatar = Boolean(peer?.avatarPhotoId);
|
||||
|
||||
const canAutoPlayGifs = selectPerformanceSettingsValue(global, 'autoplayGifs');
|
||||
|
||||
return {
|
||||
theme: selectTheme(global),
|
||||
isChannel,
|
||||
@ -1315,6 +1361,9 @@ export default memo(withGlobal<OwnProps>(
|
||||
commonChatIds: commonChats?.ids,
|
||||
monoforumChannel,
|
||||
hasAvatar,
|
||||
mainTab: peerFullInfo?.mainTab,
|
||||
canUpdateMainTab: selectCanUpdateMainTab(global, chatId),
|
||||
canAutoPlayGifs,
|
||||
};
|
||||
},
|
||||
)(Profile));
|
||||
|
||||
@ -89,6 +89,10 @@ export default function useProfileViewportIds({
|
||||
'media', resultType, searchMessages, chatMessages, foundIds, threadId,
|
||||
);
|
||||
|
||||
const [gifViewportIds, getMoreGifs, noProfileInfoForGifs] = useInfiniteScrollForSharedMedia(
|
||||
'gif', resultType, searchMessages, chatMessages, foundIds, threadId,
|
||||
);
|
||||
|
||||
const [documentViewportIds, getMoreDocuments, noProfileInfoForDocuments] = useInfiniteScrollForSharedMedia(
|
||||
'documents', resultType, searchMessages, chatMessages, foundIds, threadId,
|
||||
);
|
||||
@ -153,6 +157,11 @@ export default function useProfileViewportIds({
|
||||
getMore = getMoreMedia;
|
||||
noProfileInfo = noProfileInfoForMedia;
|
||||
break;
|
||||
case 'gif':
|
||||
viewportIds = gifViewportIds;
|
||||
getMore = getMoreGifs;
|
||||
noProfileInfo = noProfileInfoForGifs;
|
||||
break;
|
||||
case 'documents':
|
||||
viewportIds = documentViewportIds;
|
||||
getMore = getMoreDocuments;
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
import type { ElementRef } from '../../../lib/teact/teact';
|
||||
import { useEffect } from '../../../lib/teact/teact';
|
||||
|
||||
import { requestMeasure, requestMutation } from '../../../lib/fasterdom/fasterdom';
|
||||
|
||||
import useLastCallback from '../../../hooks/useLastCallback';
|
||||
import { requestMutation } from '../../../lib/fasterdom/fasterdom';
|
||||
|
||||
export default function useTransitionFixes(
|
||||
containerRef: ElementRef<HTMLDivElement>,
|
||||
@ -32,28 +30,4 @@ export default function useTransitionFixes(
|
||||
window.removeEventListener('resize', setMinHeight, false);
|
||||
};
|
||||
}, [containerRef, transitionElSelector]);
|
||||
|
||||
// Workaround for scrollable content flickering during animation.
|
||||
const applyTransitionFix = useLastCallback(() => {
|
||||
// This callback is called from `Transition.onStart` which is "mutate" phase
|
||||
requestMeasure(() => {
|
||||
const container = containerRef.current!;
|
||||
if (container.style.overflowY === 'hidden') return;
|
||||
|
||||
const scrollBarWidth = container.offsetWidth - container.clientWidth;
|
||||
|
||||
requestMutation(() => {
|
||||
container.style.overflowY = 'hidden';
|
||||
container.style.paddingRight = `${scrollBarWidth}px`;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const releaseTransitionFix = useLastCallback(() => {
|
||||
const container = containerRef.current!;
|
||||
container.style.overflowY = 'scroll';
|
||||
container.style.paddingRight = '0';
|
||||
});
|
||||
|
||||
return { applyTransitionFix, releaseTransitionFix };
|
||||
}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import type { FC, TeactNode } from '../../lib/teact/teact';
|
||||
import type React from '../../lib/teact/teact';
|
||||
import type { TeactNode } from '../../lib/teact/teact';
|
||||
import { useEffect, useLayoutEffect, useRef } from '../../lib/teact/teact';
|
||||
|
||||
import type { MenuItemContextAction } from './ListItem';
|
||||
@ -40,7 +39,7 @@ const classNames = {
|
||||
badgeActive: 'Tab__badge--active',
|
||||
};
|
||||
|
||||
const Tab: FC<OwnProps> = ({
|
||||
const Tab = ({
|
||||
className,
|
||||
title,
|
||||
isActive,
|
||||
@ -48,11 +47,11 @@ const Tab: FC<OwnProps> = ({
|
||||
badgeCount,
|
||||
isBadgeActive,
|
||||
previousActiveTab,
|
||||
onClick,
|
||||
clickArg,
|
||||
contextActions,
|
||||
contextRootElementSelector,
|
||||
}) => {
|
||||
clickArg,
|
||||
onClick,
|
||||
}: OwnProps) => {
|
||||
const tabRef = useRef<HTMLDivElement>();
|
||||
|
||||
useLayoutEffect(() => {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import type { FC, TeactNode } from '../../lib/teact/teact';
|
||||
import type { TeactNode } from '../../lib/teact/teact';
|
||||
import { memo, useEffect, useRef } from '../../lib/teact/teact';
|
||||
|
||||
import type { MenuItemContextAction } from './ListItem';
|
||||
@ -37,10 +37,14 @@ const TAB_SCROLL_THRESHOLD_PX = 16;
|
||||
// Should match duration from `--slide-transition` CSS variable
|
||||
const SCROLL_DURATION = IS_IOS ? 450 : IS_ANDROID ? 400 : 300;
|
||||
|
||||
const TabList: FC<OwnProps> = ({
|
||||
tabs, activeTab, onSwitchTab,
|
||||
contextRootElementSelector, className, tabClassName,
|
||||
}) => {
|
||||
const TabList = ({
|
||||
tabs,
|
||||
activeTab,
|
||||
className,
|
||||
tabClassName,
|
||||
contextRootElementSelector,
|
||||
onSwitchTab,
|
||||
}: OwnProps) => {
|
||||
const containerRef = useRef<HTMLDivElement>();
|
||||
const previousActiveTab = usePreviousDeprecated(activeTab);
|
||||
|
||||
|
||||
@ -118,6 +118,7 @@ import {
|
||||
selectIsCurrentUserFrozen,
|
||||
selectLastServiceNotification,
|
||||
selectPeer,
|
||||
selectPeerFullInfo,
|
||||
selectSimilarChannelIds,
|
||||
selectStickerSet,
|
||||
selectSupportChat,
|
||||
@ -3061,6 +3062,32 @@ addActionHandler('toggleAutoTranslation', async (global, actions, payload): Prom
|
||||
setGlobal(global);
|
||||
});
|
||||
|
||||
addActionHandler('setMainProfileTab', async (global, actions, payload): Promise<void> => {
|
||||
const { chatId, tab } = payload;
|
||||
const chat = selectChat(global, chatId);
|
||||
if (!chat) return;
|
||||
|
||||
const peerFullInfo = selectPeerFullInfo(global, chatId);
|
||||
const oldMainTab = peerFullInfo?.mainTab;
|
||||
if (oldMainTab === tab) return;
|
||||
|
||||
global = updatePeerFullInfo(global, chatId, { mainTab: tab });
|
||||
setGlobal(global);
|
||||
|
||||
let result;
|
||||
if (chatId === global.currentUserId) {
|
||||
result = await callApi('setAccountMainProfileTab', { tab });
|
||||
} else {
|
||||
result = await callApi('setChannelMainProfileTab', { chat, tab });
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
global = getGlobal();
|
||||
global = updatePeerFullInfo(global, chatId, { mainTab: oldMainTab });
|
||||
setGlobal(global);
|
||||
}
|
||||
});
|
||||
|
||||
addActionHandler('resolveBusinessChatLink', async (global, actions, payload): Promise<void> => {
|
||||
const { slug, tabId = getCurrentTabId() } = payload;
|
||||
const result = await callApi('resolveBusinessChatLink', { slug });
|
||||
|
||||
@ -12,7 +12,7 @@ import { getCurrentTabId } from '../../../util/establishMultitabRole';
|
||||
import { buildCollectionByKey, isInsideSortedArrayRange } from '../../../util/iteratees';
|
||||
import { getSearchResultKey } from '../../../util/keys/searchResultKey';
|
||||
import { callApi } from '../../../api/gramjs';
|
||||
import { getChatMediaMessageIds, getIsSavedDialog, isSameReaction } from '../../helpers';
|
||||
import { getIsSavedDialog, getMessageContentIds, isSameReaction } from '../../helpers';
|
||||
import {
|
||||
addActionHandler, getGlobal, setGlobal,
|
||||
} from '../../index';
|
||||
@ -479,7 +479,7 @@ async function searchChatMedia<T extends GlobalState>(
|
||||
|
||||
const loadingState = calcLoadingState(direction, limit, newFoundIds.length, currentSegment);
|
||||
|
||||
const filteredIds = getChatMediaMessageIds(byId, newFoundIds, false);
|
||||
const filteredIds = getMessageContentIds(byId, newFoundIds, 'inlineMedia');
|
||||
currentSegment = mergeWithChatMediaSearchSegment(
|
||||
filteredIds,
|
||||
loadingState,
|
||||
|
||||
@ -429,12 +429,6 @@ export function hasMediaLocalBlobUrl(media: ApiPhoto | ApiVideo | ApiDocument) {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function getChatMediaMessageIds(
|
||||
messages: Record<number, ApiMessage>, listedIds: number[], isFromSharedMedia = false,
|
||||
) {
|
||||
return getMessageContentIds(messages, listedIds, isFromSharedMedia ? 'media' : 'inlineMedia');
|
||||
}
|
||||
|
||||
export function getPhotoFullDimensions(photo: Pick<ApiPhoto, 'sizes' | 'thumbnail'>): ApiDimensions | undefined {
|
||||
return (
|
||||
photo.sizes.find((size) => size.type === 'w')
|
||||
@ -488,6 +482,13 @@ export function getMessageContentIds(
|
||||
validator = getMessageDocument;
|
||||
break;
|
||||
|
||||
case 'gif':
|
||||
validator = (message: ApiMessage) => {
|
||||
const video = getMessageVideo(message);
|
||||
return video?.isGif;
|
||||
};
|
||||
break;
|
||||
|
||||
case 'links':
|
||||
validator = (message: ApiMessage) => getMessageWebPage(message) || matchLinkInMessageText(message);
|
||||
break;
|
||||
|
||||
@ -4,7 +4,7 @@ import type { GlobalState, TabArgs } from '../types';
|
||||
import { SERVICE_NOTIFICATIONS_USER_ID } from '../../config';
|
||||
import { isUserId } from '../../util/entities/ids';
|
||||
import { getCurrentTabId } from '../../util/establishMultitabRole';
|
||||
import { isChatAdmin, isDeletedUser } from '../helpers';
|
||||
import { getHasAdminRight, isChatAdmin, isChatChannel, isDeletedUser } from '../helpers';
|
||||
import { selectChat, selectChatFullInfo } from './chats';
|
||||
import { type ProfileCollectionKey } from './payments';
|
||||
import { selectTabState } from './tabs';
|
||||
@ -74,3 +74,12 @@ export function selectPeerHasProfileBackground<T extends GlobalState>(global: T,
|
||||
const peer = selectPeer(global, peerId);
|
||||
return Boolean(peer?.profileColor || peer?.emojiStatus?.type === 'collectible');
|
||||
}
|
||||
|
||||
export function selectCanUpdateMainTab<T extends GlobalState>(global: T, peerId: string) {
|
||||
if (global.currentUserId === peerId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const chat = selectChat(global, peerId);
|
||||
return Boolean(chat && isChatChannel(chat) && getHasAdminRight(chat, 'postMessages'));
|
||||
}
|
||||
|
||||
@ -37,6 +37,7 @@ import type {
|
||||
ApiPreparedInlineMessage,
|
||||
ApiPrivacyKey,
|
||||
ApiPrivacySettings,
|
||||
ApiProfileTab,
|
||||
ApiReaction,
|
||||
ApiReactionWithPaid,
|
||||
ApiReportReason,
|
||||
@ -1142,6 +1143,10 @@ export interface ActionPayloads {
|
||||
chatId: string;
|
||||
isEnabled: boolean;
|
||||
} & WithTabId;
|
||||
setMainProfileTab: {
|
||||
chatId: string;
|
||||
tab: ApiProfileTab;
|
||||
};
|
||||
|
||||
updateChat: {
|
||||
chatId: string;
|
||||
|
||||
@ -10,6 +10,7 @@ import type {
|
||||
ApiCheckedGiftCode,
|
||||
ApiCollectibleInfo,
|
||||
ApiContact,
|
||||
ApiEmojiStatusCollectible,
|
||||
ApiError,
|
||||
ApiFormattedText,
|
||||
ApiGeoPoint,
|
||||
@ -54,7 +55,6 @@ import type {
|
||||
ApiUser,
|
||||
ApiVideo,
|
||||
} from '../../api/types';
|
||||
import type { ApiEmojiStatusCollectible } from '../../api/types/users';
|
||||
import type { FoldersActions } from '../../hooks/reducers/useFoldersReducer';
|
||||
import type { ReducerAction } from '../../hooks/useReducer';
|
||||
import type {
|
||||
|
||||
@ -9,7 +9,7 @@ import { getGlobal } from '../../global';
|
||||
import type { AnimationLevel } from '../../types';
|
||||
import type { VTTypes } from '../../util/animations/viewTransitionTypes';
|
||||
|
||||
import { VT_CLASS_NAME, VT_TYPE_CLASS_PREFIX } from '../../config';
|
||||
import { ANIMATION_LEVEL_MED, VT_CLASS_NAME, VT_TYPE_CLASS_PREFIX } from '../../config';
|
||||
import { requestMutation, requestNextMutation } from '../../lib/fasterdom/fasterdom';
|
||||
import { selectSharedSettings } from '../../global/selectors/sharedState';
|
||||
import { IS_VIEW_TRANSITION_SUPPORTED } from '../../util/browser/windowEnvironment';
|
||||
@ -98,7 +98,7 @@ export function useViewTransition(): ViewTransitionController {
|
||||
function startViewTransition(
|
||||
types: VTTypes,
|
||||
updateCallback?: TransitionFunction,
|
||||
minimumAnimationLevel: AnimationLevel = 1,
|
||||
minimumAnimationLevel: AnimationLevel = ANIMATION_LEVEL_MED,
|
||||
): PromiseLike<void> | void {
|
||||
const global = getGlobal();
|
||||
const { animationLevel } = selectSharedSettings(global);
|
||||
|
||||
@ -1537,6 +1537,7 @@ account.toggleSponsoredMessages#b9d9a38d enabled:Bool = Bool;
|
||||
account.getCollectibleEmojiStatuses#2e7b4543 hash:long = account.EmojiStatuses;
|
||||
account.getPaidMessagesRevenue#19ba4a67 flags:# parent_peer:flags.0?InputPeer user_id:InputUser = account.PaidMessagesRevenue;
|
||||
account.toggleNoPaidMessagesException#fe2eda76 flags:# refund_charged:flags.0?true require_payment:flags.2?true parent_peer:flags.1?InputPeer user_id:InputUser = Bool;
|
||||
account.setMainProfileTab#5dee78b0 tab:ProfileTab = Bool;
|
||||
users.getUsers#d91a548 id:Vector<InputUser> = Vector<User>;
|
||||
users.getFullUser#b60f5918 id:InputUser = users.UserFull;
|
||||
contacts.getContacts#5dd69e12 hash:long = contacts.Contacts;
|
||||
@ -1770,6 +1771,7 @@ channels.searchPosts#f2c4f24d flags:# hashtag:flags.0?string query:flags.1?strin
|
||||
channels.updatePaidMessagesPrice#4b12327b flags:# broadcast_messages_allowed:flags.0?true channel:InputChannel send_paid_messages_stars:long = Updates;
|
||||
channels.toggleAutotranslation#167fc0a1 channel:InputChannel enabled:Bool = Updates;
|
||||
channels.checkSearchPostsFlood#22567115 flags:# query:flags.0?string = SearchPostsFlood;
|
||||
channels.setMainProfileTab#3583fcb1 channel:InputChannel tab:ProfileTab = Bool;
|
||||
bots.setBotInfo#10cf3123 flags:# bot:flags.2?InputUser lang_code:string name:flags.3?string about:flags.0?string description:flags.1?string = Bool;
|
||||
bots.canSendMessage#1359f4e6 bot:InputUser = Bool;
|
||||
bots.allowSendMessage#f132e3ef bot:InputUser = Updates;
|
||||
|
||||
@ -66,6 +66,7 @@
|
||||
"account.getPaidMessagesRevenue",
|
||||
"account.getAccountTTL",
|
||||
"account.setAccountTTL",
|
||||
"account.setMainProfileTab",
|
||||
"users.getUsers",
|
||||
"users.getFullUser",
|
||||
"contacts.getContacts",
|
||||
@ -288,6 +289,7 @@
|
||||
"channels.updatePaidMessagesPrice",
|
||||
"channels.checkSearchPostsFlood",
|
||||
"channels.toggleAutotranslation",
|
||||
"channels.setMainProfileTab",
|
||||
"bots.getBotRecommendations",
|
||||
"bots.canSendMessage",
|
||||
"bots.allowSendMessage",
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -394,13 +394,14 @@ export type ProfileTabType =
|
||||
| 'links'
|
||||
| 'audio'
|
||||
| 'voice'
|
||||
| 'gif'
|
||||
| 'stories'
|
||||
| 'storiesArchive'
|
||||
| 'similarChannels'
|
||||
| 'similarBots'
|
||||
| 'dialogs'
|
||||
| 'gifts';
|
||||
export type SharedMediaType = 'media' | 'documents' | 'links' | 'audio' | 'voice';
|
||||
export type SharedMediaType = 'media' | 'documents' | 'links' | 'audio' | 'voice' | 'gif';
|
||||
export type MiddleSearchType = 'chat' | 'myChats' | 'channels';
|
||||
export type MiddleSearchParams = {
|
||||
requestedQuery?: string;
|
||||
|
||||
3
src/types/language.d.ts
vendored
3
src/types/language.d.ts
vendored
@ -1222,6 +1222,8 @@ export interface LangPair {
|
||||
'ProfileBotOpenAppInfoLink': undefined;
|
||||
'ProfileBirthday': undefined;
|
||||
'ProfileBirthdayToday': undefined;
|
||||
'ProfileMenuSetMainTab': undefined;
|
||||
'ProfileItemSubscribers': undefined;
|
||||
'MonetizationInfoTONTitle': undefined;
|
||||
'AriaSearchOlderResult': undefined;
|
||||
'AriaSearchNewerResult': undefined;
|
||||
@ -1395,6 +1397,7 @@ export interface LangPair {
|
||||
'ProfileTabLinks': undefined;
|
||||
'ProfileTabMusic': undefined;
|
||||
'ProfileTabVoice': undefined;
|
||||
'ProfileTabGifs': undefined;
|
||||
'ProfileTabSharedGroups': undefined;
|
||||
'ProfileTabSimilarChannels': undefined;
|
||||
'ProfileTabSimilarBots': undefined;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user