Voice Chats: Indicators and service messages (#1134)
This commit is contained in:
parent
6f9b6ba3df
commit
23529106b3
@ -40,6 +40,8 @@ function buildApiChatFieldsFromPeerEntity(
|
||||
&& { username: peerEntity.username }
|
||||
),
|
||||
...(('verified' in peerEntity) && { isVerified: peerEntity.verified }),
|
||||
...(('callActive' in peerEntity) && { isCallActive: peerEntity.callActive }),
|
||||
...(('callNotEmpty' in peerEntity) && { isCallNotEmpty: peerEntity.callNotEmpty }),
|
||||
...((peerEntity instanceof GramJs.Chat || peerEntity instanceof GramJs.Channel) && {
|
||||
...(peerEntity.participantsCount && { membersCount: peerEntity.participantsCount }),
|
||||
joinDate: peerEntity.date,
|
||||
|
||||
@ -599,6 +599,13 @@ function buildAction(
|
||||
const currencySign = getCurrencySign(action.currency);
|
||||
const amount = (Number(action.totalAmount) / 100).toFixed(2);
|
||||
text = `You successfully transferred ${currencySign}${amount} to shop for %product%`;
|
||||
} else if (action instanceof GramJs.MessageActionGroupCall) {
|
||||
if (action.duration) {
|
||||
const mins = Math.max(Math.round(action.duration / 60), 1);
|
||||
text = `Voice chat ended (${mins} min${mins > 1 ? 's' : ''})`;
|
||||
} else {
|
||||
text = 'Voice chat started';
|
||||
}
|
||||
} else {
|
||||
text = '%ACTION_NOT_IMPLEMENTED%';
|
||||
}
|
||||
|
||||
@ -355,6 +355,7 @@ async function getFullChannelInfo(
|
||||
canViewParticipants,
|
||||
linkedChatId,
|
||||
hiddenPrehistory,
|
||||
call,
|
||||
} = result.fullChat;
|
||||
|
||||
const inviteLink = exportedInvite instanceof GramJs.ChatInviteExported
|
||||
@ -387,6 +388,7 @@ async function getFullChannelInfo(
|
||||
members,
|
||||
kickedMembers,
|
||||
adminMembers,
|
||||
groupCallId: call ? call.id.toString() : undefined,
|
||||
linkedChatId: linkedChatId ? getApiChatIdFromMtpPeer({ chatId: linkedChatId } as GramJs.TypePeer) : undefined,
|
||||
},
|
||||
users: [...(users || []), ...(bannedUsers || []), ...(adminUsers || [])],
|
||||
|
||||
@ -30,6 +30,10 @@ export interface ApiChat {
|
||||
isSupport?: boolean;
|
||||
photos?: ApiPhoto[];
|
||||
|
||||
// Calls
|
||||
isCallActive?: boolean;
|
||||
isCallNotEmpty?: boolean;
|
||||
|
||||
// Current user permissions
|
||||
isNotJoined?: boolean;
|
||||
isCreator?: boolean;
|
||||
@ -56,6 +60,21 @@ export interface ApiTypingStatus {
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
export interface ApiTypeGroupCall {
|
||||
joinMuted?: true;
|
||||
canChangeJoinMuted?: true;
|
||||
joinDateAsc?: true;
|
||||
scheduleStartSubscribed?: true;
|
||||
id: number;
|
||||
participantsCount: number;
|
||||
params?: any;
|
||||
title?: string;
|
||||
streamDcId?: number;
|
||||
recordStartDate?: number;
|
||||
scheduleDate?: number;
|
||||
version: number;
|
||||
}
|
||||
|
||||
export interface ApiChatFullInfo {
|
||||
about?: string;
|
||||
onlineCount?: number;
|
||||
@ -65,6 +84,7 @@ export interface ApiChatFullInfo {
|
||||
canViewMembers?: boolean;
|
||||
isPreHistoryHidden?: boolean;
|
||||
inviteLink?: string;
|
||||
groupCallId?: string;
|
||||
slowMode?: {
|
||||
seconds: number;
|
||||
nextSendDate?: number;
|
||||
|
||||
@ -52,6 +52,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
.status {
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.info {
|
||||
.title, .subtitle {
|
||||
padding-right: .125rem;
|
||||
|
||||
@ -40,6 +40,7 @@ import useEnsureMessage from '../../../hooks/useEnsureMessage';
|
||||
import useChatContextActions from '../../../hooks/useChatContextActions';
|
||||
import useFlag from '../../../hooks/useFlag';
|
||||
import useMedia from '../../../hooks/useMedia';
|
||||
import ChatCallStatus from './ChatCallStatus';
|
||||
import { ChatAnimationTypes } from './hooks';
|
||||
|
||||
import Avatar from '../../common/Avatar';
|
||||
@ -248,13 +249,18 @@ const Chat: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||
contextActions={contextActions}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<Avatar
|
||||
chat={chat}
|
||||
user={privateChatUser}
|
||||
withOnlineStatus
|
||||
isSavedMessages={privateChatUser && privateChatUser.isSelf}
|
||||
lastSyncTime={lastSyncTime}
|
||||
/>
|
||||
<div className="status">
|
||||
<Avatar
|
||||
chat={chat}
|
||||
user={privateChatUser}
|
||||
withOnlineStatus
|
||||
isSavedMessages={privateChatUser && privateChatUser.isSelf}
|
||||
lastSyncTime={lastSyncTime}
|
||||
/>
|
||||
{chat.isCallActive && (
|
||||
<ChatCallStatus isSelected={isSelected} isActive={animationLevel !== 0} />
|
||||
)}
|
||||
</div>
|
||||
<div className="info">
|
||||
<div className="title">
|
||||
<h3>{renderText(getChatTitle(lang, chat, privateChatUser))}</h3>
|
||||
|
||||
80
src/components/left/main/ChatCallStatus.scss
Normal file
80
src/components/left/main/ChatCallStatus.scss
Normal file
@ -0,0 +1,80 @@
|
||||
|
||||
@keyframes bar-animation-transform-1 {
|
||||
0% { transform: scaleY(0.33); }
|
||||
12.5% { transform: scaleY(1.66); }
|
||||
25% { transform: scaleY(0.33); }
|
||||
37.5% { transform: scaleY(1); }
|
||||
50% { transform: scaleY(0.33); }
|
||||
62.5% { transform: scaleY(1.66); }
|
||||
75% { transform: scaleY(0.33); }
|
||||
87.5% { transform: scaleY(1.66); }
|
||||
100% { transform: scaleY(0.33); }
|
||||
}
|
||||
|
||||
@keyframes bar-animation-transform-2 {
|
||||
0% { transform: scaleY(1); }
|
||||
12.5% { transform: scaleY(0.33); }
|
||||
25% { transform: scaleY(1.66); }
|
||||
37.5% { transform: scaleY(0.33); }
|
||||
50% { transform: scaleY(1); }
|
||||
62.5% { transform: scaleY(0.33); }
|
||||
75% { transform: scaleY(1.66); }
|
||||
87.5% { transform: scaleY(0.33); }
|
||||
100% { transform: scaleY(1); }
|
||||
}
|
||||
|
||||
|
||||
.ChatCallStatus {
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
bottom: 0;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border-radius: 50%;
|
||||
background-color: #0ac630;
|
||||
border: 2px solid var(--color-background);
|
||||
overflow: hidden;
|
||||
|
||||
.indicator {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
& > div {
|
||||
width: 2px;
|
||||
height: 6px;
|
||||
background: var(--color-background);
|
||||
border-radius: 1px;
|
||||
margin: 1px;
|
||||
will-change: transform;
|
||||
transform: translateZ(0);
|
||||
}
|
||||
& > div:nth-child(odd) {
|
||||
transform: scaleY(0.8);
|
||||
}
|
||||
& > div:nth-child(even) {
|
||||
transform: scaleY(1.33);
|
||||
}
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: var(--color-white);
|
||||
border-color: var(--color-chat-active);
|
||||
.indicator div{
|
||||
background-color: var(--color-chat-active);
|
||||
}
|
||||
}
|
||||
|
||||
&.active .indicator {
|
||||
div:nth-child(odd) {
|
||||
animation: bar-animation-transform-2 3.2s normal infinite;
|
||||
}
|
||||
|
||||
div:nth-child(even) {
|
||||
animation: bar-animation-transform-1 3.2s normal infinite;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
26
src/components/left/main/ChatCallStatus.tsx
Normal file
26
src/components/left/main/ChatCallStatus.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import React, { FC, memo } from '../../../lib/teact/teact';
|
||||
import buildClassName from '../../../util/buildClassName';
|
||||
|
||||
import './ChatCallStatus.scss';
|
||||
|
||||
type OwnProps = {
|
||||
isSelected?: boolean;
|
||||
isActive?: boolean;
|
||||
};
|
||||
|
||||
const ChatCallStatus: FC<OwnProps> = ({
|
||||
isSelected,
|
||||
isActive,
|
||||
}) => {
|
||||
return (
|
||||
<div className={buildClassName('ChatCallStatus', isActive && 'active', isSelected && 'selected')}>
|
||||
<div className="indicator">
|
||||
<div />
|
||||
<div />
|
||||
<div />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(ChatCallStatus);
|
||||
6
src/lib/gramjs/tl/api.d.ts
vendored
6
src/lib/gramjs/tl/api.d.ts
vendored
@ -285,7 +285,7 @@ namespace Api {
|
||||
export type TypeAccessPointRule = AccessPointRule;
|
||||
export type TypeTlsClientHello = TlsClientHello;
|
||||
export type TypeTlsBlock = TlsBlockString | TlsBlockRandom | TlsBlockZero | TlsBlockDomain | TlsBlockGrease | TlsBlockScope;
|
||||
|
||||
|
||||
|
||||
export namespace storage {
|
||||
export type TypeFileType = storage.FileUnknown | storage.FilePartial | storage.FileJpeg | storage.FileGif | storage.FilePng | storage.FilePdf | storage.FileMp3 | storage.FileMov | storage.FileMp4 | storage.FileWebp;
|
||||
@ -7001,7 +7001,7 @@ namespace Api {
|
||||
}> {
|
||||
entries: Api.TypeTlsBlock[];
|
||||
};
|
||||
|
||||
|
||||
|
||||
export namespace storage {
|
||||
export class FileUnknown extends VirtualClass<void> {};
|
||||
@ -8500,7 +8500,7 @@ namespace Api {
|
||||
}>, Api.TypeDestroySessionRes> {
|
||||
sessionId: long;
|
||||
};
|
||||
|
||||
|
||||
|
||||
export namespace auth {
|
||||
export class SendCode extends Request<Partial<{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user