Дизайн звонков
This commit is contained in:
@@ -6,9 +6,8 @@ import { ConfirmSeed } from './views/ConfirmSeed/ConfirmSeed';
|
||||
import { SetPassword } from './views/SetPassword/SetPassword';
|
||||
import { Main } from './views/Main/Main';
|
||||
import { ExistsSeed } from './views/ExistsSeed/ExistsSeed';
|
||||
import { Box, Divider } from '@mantine/core';
|
||||
import { Box } from '@mantine/core';
|
||||
import './style.css'
|
||||
import { useRosettaColors } from './hooks/useRosettaColors';
|
||||
import { Buffer } from 'buffer';
|
||||
import { InformationProvider } from './providers/InformationProvider/InformationProvider';
|
||||
import { BlacklistProvider } from './providers/BlacklistProvider/BlacklistProvider';
|
||||
@@ -27,8 +26,6 @@ window.Buffer = Buffer;
|
||||
|
||||
export default function App() {
|
||||
const { allAccounts, accountProviderLoaded } = useAccountProvider();
|
||||
const colors = useRosettaColors();
|
||||
|
||||
|
||||
const getViewByLoginState = () => {
|
||||
if (!accountProviderLoaded) {
|
||||
@@ -59,7 +56,6 @@ export default function App() {
|
||||
<SystemAccountProvider>
|
||||
<Box h={'100%'}>
|
||||
<Topbar></Topbar>
|
||||
<Divider color={colors.borderColor}></Divider>
|
||||
<ContextMenuProvider>
|
||||
<ImageViwerProvider>
|
||||
<AvatarProvider>
|
||||
|
||||
42
app/components/ActiveCall/ActiveCall.module.css
Normal file
42
app/components/ActiveCall/ActiveCall.module.css
Normal file
@@ -0,0 +1,42 @@
|
||||
.active {
|
||||
background: linear-gradient(90deg,rgba(0, 186, 59, 1) 0%, rgba(0, 194, 81, 1) 50%);
|
||||
background-size: 200% 200%;
|
||||
animation: activeFlow 5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes activeFlow {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
filter: saturate(1);
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
filter: saturate(1.15);
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
filter: saturate(1);
|
||||
}
|
||||
}
|
||||
|
||||
.connecting {
|
||||
background: linear-gradient(120deg, #ff2d2d, #ff7a00, #ff2d2d);
|
||||
background-size: 220% 220%;
|
||||
animation: connectingFlow 5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes connectingFlow {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
filter: saturate(1);
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
filter: saturate(1.15);
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
filter: saturate(1);
|
||||
}
|
||||
}
|
||||
/* ...existing code... */
|
||||
95
app/components/ActiveCall/ActiveCall.tsx
Normal file
95
app/components/ActiveCall/ActiveCall.tsx
Normal file
@@ -0,0 +1,95 @@
|
||||
import { useCalls } from "@/app/providers/CallProvider/useCalls";
|
||||
import { useUserInformation } from "@/app/providers/InformationProvider/useUserInformation";
|
||||
import { Box, Flex, Loader, Text } from "@mantine/core";
|
||||
import classes from "./ActiveCall.module.css";
|
||||
import { CallState } from "@/app/providers/CallProvider/CallProvider";
|
||||
import { IconMicrophone, IconMicrophoneOff, IconPhoneX, IconVolume, IconVolumeOff } from "@tabler/icons-react";
|
||||
import { translateDurationToTime } from "@/app/providers/CallProvider/translateDurationTime";
|
||||
|
||||
export function ActiveCall() {
|
||||
const {activeCall, callState, duration, muted, sound, close, setMuted, setSound, setShowCallView} = useCalls();
|
||||
const [userInfo] = useUserInformation(activeCall);
|
||||
//const colors = useRosettaColors();
|
||||
|
||||
if(activeCall == ""){
|
||||
return <></>
|
||||
}
|
||||
|
||||
const getConnectingClass = () => {
|
||||
if(callState === CallState.CONNECTING){
|
||||
return classes.connecting;
|
||||
}
|
||||
if(callState === CallState.ACTIVE){
|
||||
return classes.active;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box py={4} style={{
|
||||
cursor: 'pointer'
|
||||
}} px={10} className={getConnectingClass()} onClick={() => setShowCallView(true)}>
|
||||
<Flex align={'center'} justify={'row'} gap={10}>
|
||||
<Flex w={'100%'} justify={'space-between'} align={'center'}>
|
||||
<Flex>
|
||||
{!muted && (
|
||||
<IconMicrophoneOff style={{
|
||||
cursor: 'pointer'
|
||||
}} onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setMuted(true);
|
||||
}} size={16} color={'#fff'}></IconMicrophoneOff>
|
||||
)}
|
||||
{muted && (
|
||||
<IconMicrophone style={{
|
||||
cursor: 'pointer'
|
||||
}} onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setMuted(false);
|
||||
}} size={16} color={'#fff'}></IconMicrophone>
|
||||
)}
|
||||
</Flex>
|
||||
<Flex justify={'center'} align={'center'} gap={'xs'}>
|
||||
<Text fw={500} c={'#fff'} style={{
|
||||
userSelect: 'none'
|
||||
}} fz={13}>{userInfo?.title || activeCall}</Text>
|
||||
{callState === CallState.CONNECTING && (
|
||||
<Loader type={'dots'} size={12} color="white"></Loader>
|
||||
)}
|
||||
{callState == CallState.ACTIVE && (
|
||||
<Text fw={500} c={'#ffffff'} style={{
|
||||
userSelect: 'none'
|
||||
}} fz={12}>{translateDurationToTime(duration)}</Text>
|
||||
)}
|
||||
</Flex>
|
||||
<Flex gap={'xs'} align={'center'} justify={'center'}>
|
||||
{sound && (
|
||||
<IconVolumeOff style={{
|
||||
cursor: 'pointer'
|
||||
}} size={16} onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setSound(false)
|
||||
}} color={'#fff'}></IconVolumeOff>
|
||||
)}
|
||||
{!sound && (
|
||||
<IconVolume style={{
|
||||
cursor: 'pointer'
|
||||
}} size={16} onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setSound(true)
|
||||
}} color={'#fff'}></IconVolume>
|
||||
)}
|
||||
<IconPhoneX style={{
|
||||
cursor: 'pointer'
|
||||
}} onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
close();
|
||||
}} size={16} color={'#fff'}></IconPhoneX>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
}
|
||||
111
app/components/Call/Call.tsx
Normal file
111
app/components/Call/Call.tsx
Normal file
@@ -0,0 +1,111 @@
|
||||
import { useRosettaColors } from "@/app/hooks/useRosettaColors";
|
||||
import { useAvatars } from "@/app/providers/AvatarProvider/useAvatars";
|
||||
import { CallContextValue, CallState } from "@/app/providers/CallProvider/CallProvider";
|
||||
import { translateDurationToTime } from "@/app/providers/CallProvider/translateDurationTime";
|
||||
import { useUserInformation } from "@/app/providers/InformationProvider/useUserInformation";
|
||||
import { Avatar, Box, Flex, Text } from "@mantine/core";
|
||||
import { IconChevronLeft, IconMicrophone, IconMicrophoneOff, IconPhone, IconPhoneX, IconQrcode, IconVolume, IconVolumeOff, IconX } from "@tabler/icons-react";
|
||||
|
||||
export interface CallProps {
|
||||
context: CallContextValue;
|
||||
}
|
||||
|
||||
export function Call(props: CallProps) {
|
||||
const {
|
||||
activeCall,
|
||||
duration,
|
||||
callState,
|
||||
close,
|
||||
sound,
|
||||
setSound,
|
||||
setMuted,
|
||||
setShowCallView,
|
||||
muted} = props.context;
|
||||
const [userInfo] = useUserInformation(activeCall);
|
||||
const avatars = useAvatars(activeCall);
|
||||
const colors = useRosettaColors();
|
||||
|
||||
return (
|
||||
<Box pos={'absolute'} top={0} left={0} w={'100%'} h={'100vh'} style={{
|
||||
zIndex: 11,
|
||||
background: 'linear-gradient(120deg,#141414 0%, #000000 100%)',
|
||||
}}>
|
||||
<Flex h={'100%'} w={'100vw'} direction={'column'} gap={'lg'} pt={'xl'}>
|
||||
<Flex direction={'row'} w={'100%'} gap={'sm'} align={'center'} justify={'space-between'} p={'sm'}>
|
||||
<Flex style={{
|
||||
cursor: 'pointer'
|
||||
}} onClick={() => setShowCallView(false)} justify={'center'} align={'center'}>
|
||||
<IconChevronLeft size={20}></IconChevronLeft>
|
||||
<Text fw={500}>Back</Text>
|
||||
</Flex>
|
||||
<Flex>
|
||||
<IconQrcode size={24}></IconQrcode>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex direction={'column'} mt={'xl'} style={{
|
||||
userSelect: 'none'
|
||||
}} w={'100vw'} gap={'sm'} align={'center'} justify={'center'}>
|
||||
<Avatar size={128} bg={avatars.length > 0 ? '#fff' : undefined} src={avatars.length > 0 ? avatars[0].avatar : undefined} color={'initials'} name={userInfo.title}></Avatar>
|
||||
<Text fz={20} fw={'bold'} c={'#FFF'}>{userInfo.title}</Text>
|
||||
{callState == CallState.ACTIVE && (<Text fz={14} c={'#FFF'}>{translateDurationToTime(duration)}</Text>)}
|
||||
{callState == CallState.CONNECTING && (<Text fz={14} c={'#FFF'}>Connecting...</Text>)}
|
||||
{callState == CallState.INCOMING && (<Text fz={14} c={'#FFF'}>Incoming call...</Text>)}
|
||||
<Flex gap={'xl'} align={'center'} justify={'center'} mt={'xl'}>
|
||||
{callState == CallState.ACTIVE || callState == CallState.CONNECTING && (
|
||||
<>
|
||||
<Box w={50} onClick={() => setSound(!sound)} style={{
|
||||
borderRadius: 25,
|
||||
cursor: 'pointer'
|
||||
}} h={50} bg={sound ? colors.chevrons.active : colors.chevrons.disabled}>
|
||||
<Flex w={'100%'} h={'100%'} justify={'center'} align={'center'}>
|
||||
{!sound && <IconVolume size={24} color={'#fff'}></IconVolume>}
|
||||
{sound && <IconVolumeOff size={24} color={'#fff'}></IconVolumeOff>}
|
||||
</Flex>
|
||||
</Box>
|
||||
<Box w={50} onClick={() => setMuted(!muted)} style={{
|
||||
borderRadius: 25,
|
||||
cursor: 'pointer'
|
||||
}} h={50} bg={!muted ? colors.chevrons.active : colors.chevrons.disabled}>
|
||||
<Flex w={'100%'} h={'100%'} justify={'center'} align={'center'}>
|
||||
{muted && <IconMicrophone size={24} color={'#fff'}></IconMicrophone>}
|
||||
{!muted && <IconMicrophoneOff size={24} color={'#fff'}></IconMicrophoneOff>}
|
||||
</Flex>
|
||||
</Box>
|
||||
<Box w={50} onClick={close} style={{
|
||||
borderRadius: 25,
|
||||
cursor: 'pointer'
|
||||
}} h={50} bg={colors.error}>
|
||||
<Flex w={'100%'} h={'100%'} justify={'center'} align={'center'}>
|
||||
<IconPhoneX size={24} color={'#fff'}></IconPhoneX>
|
||||
</Flex>
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
{callState == CallState.INCOMING && (
|
||||
<>
|
||||
{userInfo.title != "Rosetta" && (
|
||||
<Box w={50} onClick={close} style={{
|
||||
borderRadius: 25,
|
||||
cursor: 'pointer'
|
||||
}} h={50} bg={colors.error}>
|
||||
<Flex w={'100%'} h={'100%'} justify={'center'} align={'center'}>
|
||||
<IconX size={24} color={'#fff'}></IconX>
|
||||
</Flex>
|
||||
</Box>
|
||||
)}
|
||||
<Box w={userInfo.title != "Rosetta" ? 50 : 100} onClick={close} style={{
|
||||
borderRadius: '50%',
|
||||
cursor: 'pointer'
|
||||
}} h={userInfo.title != "Rosetta" ? 50 : 100} bg={colors.success}>
|
||||
<Flex w={'100%'} h={'100%'} justify={'center'} align={'center'}>
|
||||
<IconPhone size={24} color={'#fff'}></IconPhone>
|
||||
</Flex>
|
||||
</Box>
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
@@ -1,14 +1,13 @@
|
||||
import { useRosettaColors } from "@/app/hooks/useRosettaColors";
|
||||
import { OnlineState } from "@/app/providers/ProtocolProvider/protocol/packets/packet.onlinestate";
|
||||
import { usePublicKey } from "@/app/providers/AccountProvider/usePublicKey";
|
||||
import { useBlacklist } from "@/app/providers/BlacklistProvider/useBlacklist";
|
||||
import { useDialog } from "@/app/providers/DialogProvider/useDialog";
|
||||
import { useUserInformation } from "@/app/providers/InformationProvider/useUserInformation";
|
||||
import { ProtocolState } from "@/app/providers/ProtocolProvider/ProtocolProvider";
|
||||
import { useProtocolState } from "@/app/providers/ProtocolProvider/useProtocolState";
|
||||
import { Avatar, Box, Divider, Flex, Loader, Text, Tooltip, useComputedColorScheme, useMantineTheme } from "@mantine/core";
|
||||
import { Avatar, Box, Divider, Flex, Loader, Text, useComputedColorScheme, useMantineTheme } from "@mantine/core";
|
||||
import { modals } from "@mantine/modals";
|
||||
import { IconBookmark, IconLockAccess, IconLockCancel, IconTrashX } from "@tabler/icons-react";
|
||||
import { IconBookmark, IconPhone, IconTrashX } from "@tabler/icons-react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { VerifiedBadge } from "../VerifiedBadge/VerifiedBadge";
|
||||
@@ -20,6 +19,7 @@ import { ReplyHeader } from "../ReplyHeader/ReplyHeader";
|
||||
import { useRosettaBreakpoints } from "@/app/hooks/useRosettaBreakpoints";
|
||||
import { BackToDialogs } from "../BackToDialogs/BackToDialogs";
|
||||
import { useSystemAccounts } from "@/app/providers/SystemAccountsProvider/useSystemAccounts";
|
||||
import { useCalls } from "@/app/providers/CallProvider/useCalls";
|
||||
|
||||
|
||||
export function ChatHeader() {
|
||||
@@ -29,7 +29,6 @@ export function ChatHeader() {
|
||||
const publicKey = usePublicKey();
|
||||
const {deleteMessages, dialog} = useDialog();
|
||||
const theme = useMantineTheme();
|
||||
const [blocked, blockUser, unblockUser] = useBlacklist(dialog);
|
||||
const [opponent, ___, forceUpdateUserInformation] = useUserInformation(dialog);
|
||||
const [protocolState] = useProtocolState();
|
||||
const [userTypeing, setUserTypeing] = useState(false);
|
||||
@@ -39,6 +38,7 @@ export function ChatHeader() {
|
||||
const {lg} = useRosettaBreakpoints();
|
||||
const systemAccounts = useSystemAccounts();
|
||||
const isSystemAccount = systemAccounts.find((acc) => acc.publicKey == dialog) != undefined;
|
||||
const {call} = useCalls();
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
@@ -78,20 +78,6 @@ export function ChatHeader() {
|
||||
});
|
||||
}
|
||||
|
||||
const onClickBlockUser = () => {
|
||||
if(opponent.publicKey != "DELETED"
|
||||
&& opponent.publicKey != publicKey){
|
||||
blockUser();
|
||||
}
|
||||
}
|
||||
|
||||
const onClickUnblockUser = () => {
|
||||
if(opponent.publicKey != "DELETED"
|
||||
&& opponent.publicKey != publicKey){
|
||||
unblockUser();
|
||||
}
|
||||
}
|
||||
|
||||
const onClickProfile = () => {
|
||||
if(opponent.publicKey != "DELETED" && opponent.publicKey != publicKey){
|
||||
navigate("/main/profile/" + opponent.publicKey);
|
||||
@@ -149,32 +135,16 @@ export function ChatHeader() {
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Flex h={'100%'} align={'center'} gap={'sm'}>
|
||||
<Tooltip onClick={onClickClearMessages} withArrow position={'bottom'} label={"Clear all messages"}>
|
||||
<IconTrashX
|
||||
style={{
|
||||
cursor: 'pointer'
|
||||
}} stroke={1.5} color={theme.colors.blue[7]} size={24}></IconTrashX>
|
||||
</Tooltip>
|
||||
{publicKey != opponent.publicKey && !blocked && !isSystemAccount && (
|
||||
<Tooltip onClick={onClickBlockUser} withArrow position={'bottom'} label={"Block user"}>
|
||||
<IconLockCancel
|
||||
style={{
|
||||
cursor: 'pointer'
|
||||
}} stroke={1.5} color={theme.colors.red[7]} size={24}
|
||||
>
|
||||
</IconLockCancel>
|
||||
</Tooltip>
|
||||
)}
|
||||
{blocked && !isSystemAccount && (
|
||||
<Tooltip onClick={onClickUnblockUser} withArrow position={'bottom'} label={"Unblock user"}>
|
||||
<IconLockAccess
|
||||
style={{
|
||||
cursor: 'pointer'
|
||||
}} stroke={1.5} color={theme.colors.green[7]} size={24}
|
||||
>
|
||||
</IconLockAccess>
|
||||
</Tooltip>
|
||||
)}
|
||||
<IconPhone
|
||||
onClick={() => call(dialog)}
|
||||
style={{
|
||||
cursor: 'pointer'
|
||||
}} stroke={1.5} color={theme.colors.blue[7]} size={24}></IconPhone>
|
||||
<IconTrashX
|
||||
onClick={onClickClearMessages}
|
||||
style={{
|
||||
cursor: 'pointer'
|
||||
}} stroke={1.5} color={theme.colors.blue[7]} size={24}></IconTrashX>
|
||||
</Flex>
|
||||
</Flex>}
|
||||
{replyMessages.messages.length > 0 && !replyMessages.inDialogInput && <ReplyHeader></ReplyHeader>}
|
||||
|
||||
@@ -10,6 +10,8 @@ import { DialogsPanelHeader } from '../DialogsPanelHeader/DialogsPanelHeader';
|
||||
import { useDialogsList } from '@/app/providers/DialogListProvider/useDialogsList';
|
||||
import { useVerifyRequest } from '@/app/providers/DeviceProvider/useVerifyRequest';
|
||||
import { DeviceVerify } from '../DeviceVerify/DeviceVerify';
|
||||
import { ActiveCall } from '../ActiveCall/ActiveCall';
|
||||
import { useViewPanelsState, ViewPanelsState } from '@/app/hooks/useViewPanelsState';
|
||||
|
||||
export function DialogsPanel() {
|
||||
const [dialogsMode, setDialogsMode] = useState<'all' | 'requests'>('all');
|
||||
@@ -18,6 +20,7 @@ export function DialogsPanel() {
|
||||
const colors = useRosettaColors();
|
||||
const navigate = useNavigate();
|
||||
const device = useVerifyRequest();
|
||||
const [viewState] = useViewPanelsState();
|
||||
|
||||
useEffect(() => {
|
||||
((async () => {
|
||||
@@ -52,6 +55,9 @@ export function DialogsPanel() {
|
||||
direction={'column'}
|
||||
justify={'space-between'}
|
||||
>
|
||||
{viewState == ViewPanelsState.DIALOGS_PANEL_ONLY && (
|
||||
<ActiveCall></ActiveCall>
|
||||
)}
|
||||
<Box>
|
||||
<DialogsPanelHeader></DialogsPanelHeader>
|
||||
{device && (
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
left: 12px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
z-index: 10;
|
||||
z-index: 15;
|
||||
app-region: no-drag;
|
||||
}
|
||||
.close_btn, .minimize_btn, .maximize_btn {
|
||||
|
||||
70
app/providers/CallProvider/CallProvider.tsx
Normal file
70
app/providers/CallProvider/CallProvider.tsx
Normal file
@@ -0,0 +1,70 @@
|
||||
import { Call } from "@/app/components/Call/Call";
|
||||
import { createContext, useState } from "react";
|
||||
|
||||
|
||||
export interface CallContextValue {
|
||||
call: (callable: string) => void;
|
||||
close: () => void;
|
||||
activeCall: string;
|
||||
callState: CallState;
|
||||
muted: boolean;
|
||||
sound: boolean;
|
||||
setMuted: (muted: boolean) => void;
|
||||
setSound: (sound: boolean) => void;
|
||||
duration: number;
|
||||
setShowCallView: (show: boolean) => void;
|
||||
}
|
||||
|
||||
export enum CallState {
|
||||
CONNECTING,
|
||||
ACTIVE,
|
||||
ENDED,
|
||||
INCOMING
|
||||
}
|
||||
|
||||
export const CallContext = createContext<CallContextValue | null>(null);
|
||||
export interface CallProviderProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export function CallProvider(props : CallProviderProps) {
|
||||
const [activeCall, setActiveCall] = useState<string>("");
|
||||
const [callState, setCallState] = useState<CallState>(CallState.ENDED);
|
||||
const [muted, setMuted] = useState<boolean>(false);
|
||||
const [sound, setSound] = useState<boolean>(true);
|
||||
const [duration, setDuration] = useState<number>(0);
|
||||
const [showCallView, setShowCallView] = useState<boolean>(callState == CallState.INCOMING);
|
||||
|
||||
const call = (dialog: string) => {
|
||||
setActiveCall(dialog);
|
||||
setCallState(CallState.CONNECTING);
|
||||
setShowCallView(true);
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
setActiveCall("");
|
||||
setCallState(CallState.ENDED);
|
||||
setShowCallView(false);
|
||||
setDuration(0);
|
||||
}
|
||||
|
||||
const context = {
|
||||
call,
|
||||
close,
|
||||
activeCall,
|
||||
callState,
|
||||
muted,
|
||||
sound,
|
||||
setMuted,
|
||||
setSound,
|
||||
duration,
|
||||
setShowCallView
|
||||
};
|
||||
|
||||
return (
|
||||
<CallContext.Provider value={context}>
|
||||
{props.children}
|
||||
{showCallView && <Call context={context}></Call>}
|
||||
</CallContext.Provider>
|
||||
)
|
||||
}
|
||||
5
app/providers/CallProvider/translateDurationTime.ts
Normal file
5
app/providers/CallProvider/translateDurationTime.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export const translateDurationToTime = (duration: number) => {
|
||||
const minutes = Math.floor(duration / 60);
|
||||
const seconds = duration % 60;
|
||||
return `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
|
||||
}
|
||||
15
app/providers/CallProvider/useCalls.ts
Normal file
15
app/providers/CallProvider/useCalls.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { useContext } from "react";
|
||||
import { CallContext, CallContextValue } from "./CallProvider";
|
||||
|
||||
/**
|
||||
* Хук предоставляет функции для работы с звонками, такие как инициирование звонка, принятие звонка, завершение звонка и т.д.
|
||||
* Он может использоваться в компонентах, связанных с звонками, для управления состоянием звонков и взаимодействия с сервером.
|
||||
*/
|
||||
export function useCalls() : CallContextValue {
|
||||
const context = useContext(CallContext);
|
||||
if (!context) {
|
||||
throw new Error("useCalls must be used within a CallProvider");
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
@@ -9,12 +9,13 @@ import { useEffect } from "react";
|
||||
import { useViewPanelsState, ViewPanelsState } from "@/app/hooks/useViewPanelsState";
|
||||
import { GroupHeader } from "@/app/components/GroupHeader/GroupHeader";
|
||||
import { useGroups } from "@/app/providers/DialogProvider/useGroups";
|
||||
import { ActiveCall } from "@/app/components/ActiveCall/ActiveCall";
|
||||
|
||||
export function Chat() {
|
||||
const params = useParams();
|
||||
const dialog = params.id || "DELETED";
|
||||
const {lg} = useRosettaBreakpoints();
|
||||
const [__, setViewState] = useViewPanelsState();
|
||||
const [viewState, setViewState] = useViewPanelsState();
|
||||
const {hasGroup} = useGroups();
|
||||
|
||||
useEffect(() => {
|
||||
@@ -30,6 +31,9 @@ export function Chat() {
|
||||
return (<>
|
||||
<DialogProvider dialog={dialog} key={dialog}>
|
||||
<Flex direction={'column'} justify={'space-between'} h={'100%'}>
|
||||
{viewState != ViewPanelsState.DIALOGS_PANEL_ONLY && (
|
||||
<ActiveCall></ActiveCall>
|
||||
)}
|
||||
{/* Group Header */}
|
||||
{hasGroup(dialog) && <GroupHeader></GroupHeader>}
|
||||
{/* Dialog peer to peer Header */}
|
||||
|
||||
@@ -31,6 +31,7 @@ import { useUpdateMessage } from "@/app/hooks/useUpdateMessage";
|
||||
import { useDeviceMessage } from "@/app/hooks/useDeviceMessage";
|
||||
import { UpdateProvider } from "@/app/providers/UpdateProvider/UpdateProvider";
|
||||
import { useSynchronize } from "@/app/providers/DialogProvider/useSynchronize";
|
||||
import { CallProvider } from "@/app/providers/CallProvider/CallProvider";
|
||||
|
||||
export function Main() {
|
||||
const { mainColor, borderColor } = useRosettaColors();
|
||||
@@ -154,52 +155,56 @@ export function Main() {
|
||||
<SystemAccountProvider>
|
||||
<TransportProvider>
|
||||
<UpdateProvider>
|
||||
<Flex direction={'row'} style={{
|
||||
height: '100%',
|
||||
width: '100vw',
|
||||
}}>
|
||||
<div style={{
|
||||
display: viewState != ViewPanelsState.DIALOGS_PANEL_HIDE ? 'block' : 'none',
|
||||
width: viewState == ViewPanelsState.DIALOGS_PANEL_ONLY ? '100%' : '300px',
|
||||
<CallProvider>
|
||||
<Flex direction={'row'} style={{
|
||||
height: '100%',
|
||||
width: '100vw',
|
||||
}}>
|
||||
<DialogsPanel></DialogsPanel>
|
||||
</div>
|
||||
<Divider color={borderColor} orientation={'vertical'}></Divider>
|
||||
{viewState != ViewPanelsState.DIALOGS_PANEL_ONLY && <Box
|
||||
bg={mainColor}
|
||||
style={{
|
||||
flexGrow: 1,
|
||||
height: 'calc(100vh - 27px)',
|
||||
width: `calc(100% - 300px)`,
|
||||
minWidth: 0
|
||||
}}
|
||||
>
|
||||
<Routes>
|
||||
<Route path={'/chat/:id'} element={<Chat />}></Route>
|
||||
<Route path={'/profile/:id'} element={<Profile />}></Route>
|
||||
<Route path={'/'} element={<DialogPreview />}></Route>
|
||||
<Route path={'/theme'} element={<Theme />}></Route>
|
||||
<Route path={'/safety'} element={<Safety />}></Route>
|
||||
<Route path={'/update'} element={<Update />}></Route>
|
||||
<Route path={'/backup'} element={<Backup />}></Route>
|
||||
<Route path={'/dialogs'} element={<Dialogs />}></Route>
|
||||
<Route path={'/newgroup'} element={<CreateGroup />}></Route>
|
||||
<Route path={'/group/:id'} element={<GroupInfo />}></Route>
|
||||
<Route path={'/groupencrypt/:key'} element={<GroupEncryption />}></Route>
|
||||
</Routes>
|
||||
</Box>}
|
||||
</Flex>
|
||||
{oldPublicKey && (
|
||||
<Overlay blur={8} color="#333">
|
||||
<Flex direction={'column'} align={'center'} justify={'center'} h={'100%'}>
|
||||
<Alert w={400} variant="filled" color="red" title="Old account">
|
||||
Your account uses an old format public key which is no longer supported. Please create a new account to continue using the application.
|
||||
<br></br>After press "OK" button, the application will close and remove all data.
|
||||
</Alert>
|
||||
<Button w={400} mt={'md'} color="red" onClick={dropAccountsAndMessages}>OK</Button>
|
||||
</Flex>
|
||||
</Overlay>
|
||||
)}
|
||||
<div style={{
|
||||
display: viewState != ViewPanelsState.DIALOGS_PANEL_HIDE ? 'block' : 'none',
|
||||
width: viewState == ViewPanelsState.DIALOGS_PANEL_ONLY ? '100%' : '300px',
|
||||
}}>
|
||||
<DialogsPanel></DialogsPanel>
|
||||
</div>
|
||||
{lg && (
|
||||
<Divider color={borderColor} orientation={'vertical'}></Divider>
|
||||
)}
|
||||
{viewState != ViewPanelsState.DIALOGS_PANEL_ONLY && <Box
|
||||
bg={mainColor}
|
||||
style={{
|
||||
flexGrow: 1,
|
||||
height: 'calc(100vh - 27px)',
|
||||
width: `calc(100% - 300px)`,
|
||||
minWidth: 0
|
||||
}}
|
||||
>
|
||||
<Routes>
|
||||
<Route path={'/chat/:id'} element={<Chat />}></Route>
|
||||
<Route path={'/profile/:id'} element={<Profile />}></Route>
|
||||
<Route path={'/'} element={<DialogPreview />}></Route>
|
||||
<Route path={'/theme'} element={<Theme />}></Route>
|
||||
<Route path={'/safety'} element={<Safety />}></Route>
|
||||
<Route path={'/update'} element={<Update />}></Route>
|
||||
<Route path={'/backup'} element={<Backup />}></Route>
|
||||
<Route path={'/dialogs'} element={<Dialogs />}></Route>
|
||||
<Route path={'/newgroup'} element={<CreateGroup />}></Route>
|
||||
<Route path={'/group/:id'} element={<GroupInfo />}></Route>
|
||||
<Route path={'/groupencrypt/:key'} element={<GroupEncryption />}></Route>
|
||||
</Routes>
|
||||
</Box>}
|
||||
</Flex>
|
||||
{oldPublicKey && (
|
||||
<Overlay blur={8} color="#333">
|
||||
<Flex direction={'column'} align={'center'} justify={'center'} h={'100%'}>
|
||||
<Alert w={400} variant="filled" color="red" title="Old account">
|
||||
Your account uses an old format public key which is no longer supported. Please create a new account to continue using the application.
|
||||
<br></br>After press "OK" button, the application will close and remove all data.
|
||||
</Alert>
|
||||
<Button w={400} mt={'md'} color="red" onClick={dropAccountsAndMessages}>OK</Button>
|
||||
</Flex>
|
||||
</Overlay>
|
||||
)}
|
||||
</CallProvider>
|
||||
</UpdateProvider>
|
||||
</TransportProvider>
|
||||
</SystemAccountProvider>
|
||||
|
||||
Reference in New Issue
Block a user