make resizable the height of the inconvo call

pull/2015/head
Audric Ackermann 4 years ago
parent 1f11872870
commit 0f21e12073
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -115,15 +115,6 @@
border-left: var(--border-session); border-left: var(--border-session);
border-top: var(--border-session); border-top: var(--border-session);
&__blocking-overlay {
background-color: rgba(0, 0, 0, 0.8);
position: absolute;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
}
} }
.conversation-info-panel { .conversation-info-panel {
@ -196,6 +187,8 @@
flex-grow: 1; flex-grow: 1;
min-height: $composition-container-height; min-height: $composition-container-height;
padding: $session-margin-xs 0; padding: $session-margin-xs 0;
z-index: 1;
background-color: inherit;
ul { ul {
max-height: 70vh; max-height: 70vh;

@ -0,0 +1,119 @@
import React, { useEffect, useRef, useState } from 'react';
import styled from 'styled-components';
type SplitViewProps = {
top: React.ReactElement;
bottom: React.ReactElement;
disableTop: boolean;
};
const SlyledSplitView = styled.div`
height: 100%;
display: flex;
flex-direction: column;
`;
const SplitViewDivider = styled.div`
width: calc(100% - 2rem);
height: 2px;
margin: 1rem;
border: 2px solid #808080;
cursor: row-resize;
flex-shrink: 0;
`;
const StyledTop = styled.div`
background: red;
display: flex;
flex-direction: column;
`;
const TopSplitViewPanel = ({
children,
topHeight,
setTopHeight,
}: {
children: React.ReactNode;
topHeight: number | undefined;
setTopHeight: (value: number) => void;
}) => {
const topRef = useRef<HTMLDivElement>(null);
React.useEffect(() => {
if (topRef.current) {
if (!topHeight) {
setTopHeight(Math.max(MIN_HEIGHT_TOP, topRef.current?.clientHeight / 2));
return;
}
topRef.current.style.height = `${topHeight}px`;
}
}, [topRef, topHeight, setTopHeight]);
return <StyledTop ref={topRef}>{children}</StyledTop>;
};
const MIN_HEIGHT_TOP = 300;
const MIN_HEIGHT_BOTTOM = 0;
export const SplitViewContainer: React.FunctionComponent<SplitViewProps> = ({
disableTop,
top,
bottom,
}) => {
const [topHeight, setTopHeight] = useState<undefined | number>(undefined);
const [separatorYPosition, setSeparatorYPosition] = useState<undefined | number>(undefined);
const [dragging, setDragging] = useState(false);
const splitPaneRef = useRef<HTMLDivElement | null>(null);
const onMouseDown = (e: any) => {
setSeparatorYPosition(e.clientY);
setDragging(true);
};
const onMouseMove = (e: any) => {
if (dragging && topHeight && separatorYPosition) {
const newTopHeight = topHeight + e.clientY - separatorYPosition;
setSeparatorYPosition(e.clientY);
if (newTopHeight < MIN_HEIGHT_TOP) {
setTopHeight(MIN_HEIGHT_TOP);
return;
}
if (splitPaneRef.current) {
const splitPaneHeight = splitPaneRef.current.clientHeight;
if (newTopHeight > splitPaneHeight - MIN_HEIGHT_BOTTOM) {
setTopHeight(splitPaneHeight - MIN_HEIGHT_BOTTOM);
return;
}
}
setTopHeight(newTopHeight);
}
};
useEffect(() => {
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
return () => {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
};
});
const onMouseUp = () => {
setDragging(false);
};
return (
<SlyledSplitView ref={splitPaneRef}>
{!disableTop && (
<TopSplitViewPanel topHeight={topHeight} setTopHeight={setTopHeight}>
{top}
<SplitViewDivider onMouseDown={onMouseDown} />
</TopSplitViewPanel>
)}
{bottom}
</SlyledSplitView>
);
};

@ -6,9 +6,7 @@ import { useVideoCallEventsListener } from '../../../hooks/useVideoEventListener
import { setFullScreenCall } from '../../../state/ducks/conversations'; import { setFullScreenCall } from '../../../state/ducks/conversations';
import { import {
getCallIsInFullScreen, getCallIsInFullScreen,
getHasOngoingCall, getHasOngoingCallWithFocusedConvo,
getHasOngoingCallWithPubkey,
getSelectedConversationKey,
} from '../../../state/selectors/conversations'; } from '../../../state/selectors/conversations';
import { StyledVideoElement } from './DraggableCallContainer'; import { StyledVideoElement } from './DraggableCallContainer';
@ -28,9 +26,7 @@ const CallInFullScreenVisible = styled.div`
export const CallInFullScreenContainer = () => { export const CallInFullScreenContainer = () => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const ongoingCallPubkey = useSelector(getHasOngoingCallWithPubkey); const ongoingCallWithFocused = useSelector(getHasOngoingCallWithFocusedConvo);
const selectedConversationKey = useSelector(getSelectedConversationKey);
const hasOngoingCall = useSelector(getHasOngoingCall);
const hasOngoingCallFullScreen = useSelector(getCallIsInFullScreen); const hasOngoingCallFullScreen = useSelector(getCallIsInFullScreen);
const { remoteStream, remoteStreamVideoIsMuted } = useVideoCallEventsListener( const { remoteStream, remoteStreamVideoIsMuted } = useVideoCallEventsListener(
@ -55,12 +51,7 @@ export const CallInFullScreenContainer = () => {
} }
}, [remoteStreamVideoIsMuted]); }, [remoteStreamVideoIsMuted]);
if ( if (!ongoingCallWithFocused || !hasOngoingCallFullScreen) {
!hasOngoingCall ||
!ongoingCallPubkey ||
!hasOngoingCallFullScreen ||
selectedConversationKey !== ongoingCallPubkey
) {
return null; return null;
} }

@ -5,10 +5,9 @@ import styled from 'styled-components';
import _ from 'underscore'; import _ from 'underscore';
import { CallManager, ToastUtils, UserUtils } from '../../../session/utils'; import { CallManager, ToastUtils, UserUtils } from '../../../session/utils';
import { import {
getHasOngoingCall,
getHasOngoingCallWith, getHasOngoingCallWith,
getHasOngoingCallWithFocusedConvo,
getHasOngoingCallWithPubkey, getHasOngoingCallWithPubkey,
getSelectedConversationKey,
} from '../../../state/selectors/conversations'; } from '../../../state/selectors/conversations';
import { SessionIconButton } from '../icon'; import { SessionIconButton } from '../icon';
import { animation, contextMenu, Item, Menu } from 'react-contexify'; import { animation, contextMenu, Item, Menu } from 'react-contexify';
@ -32,11 +31,11 @@ const VideoContainer = styled.div`
const InConvoCallWindow = styled.div` const InConvoCallWindow = styled.div`
padding: 1rem; padding: 1rem;
display: flex; display: flex;
height: 50%; /* height: 50%; */
background-color: hsl(0, 0%, 15.7%); background-color: hsl(0, 0%, 15.7%);
flex-shrink: 0; flex-shrink: 1;
min-height: 200px; min-height: 200px;
align-items: center; align-items: center;
`; `;
@ -248,10 +247,9 @@ const handleMicrophoneToggle = async (
// tslint:disable-next-line: max-func-body-length // tslint:disable-next-line: max-func-body-length
export const InConversationCallContainer = () => { export const InConversationCallContainer = () => {
const ongoingCallProps = useSelector(getHasOngoingCallWith); const ongoingCallProps = useSelector(getHasOngoingCallWith);
const selectedConversationKey = useSelector(getSelectedConversationKey);
const hasOngoingCall = useSelector(getHasOngoingCall);
const ongoingCallPubkey = useSelector(getHasOngoingCallWithPubkey); const ongoingCallPubkey = useSelector(getHasOngoingCallWithPubkey);
const ongoingCallWithFocused = useSelector(getHasOngoingCallWithFocusedConvo);
const ongoingCallUsername = ongoingCallProps?.profileName || ongoingCallProps?.name; const ongoingCallUsername = ongoingCallProps?.profileName || ongoingCallProps?.name;
const videoRefRemote = useRef<HTMLVideoElement>(null); const videoRefRemote = useRef<HTMLVideoElement>(null);
const videoRefLocal = useRef<HTMLVideoElement>(null); const videoRefLocal = useRef<HTMLVideoElement>(null);
@ -278,7 +276,7 @@ export const InConversationCallContainer = () => {
videoRefLocal.current.srcObject = localStream; videoRefLocal.current.srcObject = localStream;
} }
if (!hasOngoingCall || !ongoingCallProps || ongoingCallPubkey !== selectedConversationKey) { if (!ongoingCallWithFocused) {
return null; return null;
} }

@ -14,7 +14,6 @@ import { AttachmentUtil, GoogleChrome } from '../../../util';
import { ConversationHeaderWithDetails } from '../../conversation/ConversationHeader'; import { ConversationHeaderWithDetails } from '../../conversation/ConversationHeader';
import { SessionRightPanelWithDetails } from './SessionRightPanel'; import { SessionRightPanelWithDetails } from './SessionRightPanel';
import { SessionTheme } from '../../../state/ducks/SessionTheme'; import { SessionTheme } from '../../../state/ducks/SessionTheme';
import styled from 'styled-components';
import { SessionMessagesListContainer } from './SessionMessagesListContainer'; import { SessionMessagesListContainer } from './SessionMessagesListContainer';
import { LightboxGallery, MediaItemType } from '../../LightboxGallery'; import { LightboxGallery, MediaItemType } from '../../LightboxGallery';
@ -34,16 +33,11 @@ import { MessageDetail } from '../../conversation/MessageDetail';
import { getConversationController } from '../../../session/conversations'; import { getConversationController } from '../../../session/conversations';
import { getPubkeysInPublicConversation } from '../../../data/data'; import { getPubkeysInPublicConversation } from '../../../data/data';
import autoBind from 'auto-bind'; import autoBind from 'auto-bind';
import { useSelector } from 'react-redux';
import {
getFirstUnreadMessageId,
isFirstUnreadMessageIdAbove,
} from '../../../state/selectors/conversations';
import { SessionButtonColor } from '../SessionButton'; import { SessionButtonColor } from '../SessionButton';
import { updateConfirmModal } from '../../../state/ducks/modalDialog'; import { updateConfirmModal } from '../../../state/ducks/modalDialog';
import { addStagedAttachmentsInConversation } from '../../../state/ducks/stagedAttachments'; import { addStagedAttachmentsInConversation } from '../../../state/ducks/stagedAttachments';
import { InConversationCallContainer } from '../calling/InConversationCallContainer'; import { InConversationCallContainer } from '../calling/InConversationCallContainer';
import { SplitViewContainer } from '../SplitViewContainer';
interface State { interface State {
showRecordingView: boolean; showRecordingView: boolean;
@ -62,6 +56,7 @@ interface Props {
selectedMessages: Array<string>; selectedMessages: Array<string>;
showMessageDetails: boolean; showMessageDetails: boolean;
isRightPanelShowing: boolean; isRightPanelShowing: boolean;
hasOngoingCallWithFocusedConvo: boolean;
// lightbox options // lightbox options
lightBoxOptions?: LightBoxOptions; lightBoxOptions?: LightBoxOptions;
@ -69,30 +64,6 @@ interface Props {
stagedAttachments: Array<StagedAttachmentType>; stagedAttachments: Array<StagedAttachmentType>;
} }
const SessionUnreadAboveIndicator = styled.div`
position: sticky;
top: 0;
margin: 1em;
display: flex;
justify-content: center;
background: var(--color-sent-message-background);
color: var(--color-sent-message-text);
`;
const UnreadAboveIndicator = () => {
const isFirstUnreadAbove = useSelector(isFirstUnreadMessageIdAbove);
const firstUnreadMessageId = useSelector(getFirstUnreadMessageId) as string;
if (!isFirstUnreadAbove) {
return null;
}
return (
<SessionUnreadAboveIndicator key={`above-unread-indicator-${firstUnreadMessageId}`}>
{window.i18n('latestUnreadIsAbove')}
</SessionUnreadAboveIndicator>
);
};
export class SessionConversation extends React.Component<Props, State> { export class SessionConversation extends React.Component<Props, State> {
private readonly messageContainerRef: React.RefObject<HTMLDivElement>; private readonly messageContainerRef: React.RefObject<HTMLDivElement>;
private dragCounter: number; private dragCounter: number;
@ -227,7 +198,7 @@ export class SessionConversation extends React.Component<Props, State> {
// ~~~~~~~~~~~~~~ RENDER METHODS ~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~ RENDER METHODS ~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public render() { public render() {
const { showRecordingView, isDraggingFile } = this.state; const { isDraggingFile } = this.state;
const { const {
selectedConversation, selectedConversation,
@ -264,12 +235,14 @@ export class SessionConversation extends React.Component<Props, State> {
{lightBoxOptions?.media && this.renderLightBox(lightBoxOptions)} {lightBoxOptions?.media && this.renderLightBox(lightBoxOptions)}
<div className="conversation-messages"> <div className="conversation-messages">
<InConversationCallContainer /> <SplitViewContainer
<UnreadAboveIndicator /> top={<InConversationCallContainer />}
bottom={
<SessionMessagesListContainer messageContainerRef={this.messageContainerRef} /> <SessionMessagesListContainer messageContainerRef={this.messageContainerRef} />
}
disableTop={!this.props.hasOngoingCallWithFocusedConvo}
/>
{showRecordingView && <div className="conversation-messages__blocking-overlay" />}
{isDraggingFile && <SessionFileDropzone />} {isDraggingFile && <SessionFileDropzone />}
</div> </div>

@ -18,7 +18,7 @@ import { getMessagesBySentAt } from '../../../data/data';
import autoBind from 'auto-bind'; import autoBind from 'auto-bind';
import { ConversationTypeEnum } from '../../../models/conversation'; import { ConversationTypeEnum } from '../../../models/conversation';
import { StateType } from '../../../state/reducer'; import { StateType } from '../../../state/reducer';
import { connect } from 'react-redux'; import { connect, useSelector } from 'react-redux';
import { import {
getFirstUnreadMessageId, getFirstUnreadMessageId,
getQuotedMessageToAnimate, getQuotedMessageToAnimate,
@ -26,13 +26,39 @@ import {
getSelectedConversationKey, getSelectedConversationKey,
getShowScrollButton, getShowScrollButton,
getSortedMessagesOfSelectedConversation, getSortedMessagesOfSelectedConversation,
isFirstUnreadMessageIdAbove,
} from '../../../state/selectors/conversations'; } from '../../../state/selectors/conversations';
import { SessionMessagesList } from './SessionMessagesList'; import { SessionMessagesList } from './SessionMessagesList';
import styled from 'styled-components';
export type SessionMessageListProps = { export type SessionMessageListProps = {
messageContainerRef: React.RefObject<HTMLDivElement>; messageContainerRef: React.RefObject<HTMLDivElement>;
}; };
const SessionUnreadAboveIndicator = styled.div`
position: sticky;
top: 0;
margin: 1em;
display: flex;
justify-content: center;
background: var(--color-sent-message-background);
color: var(--color-sent-message-text);
`;
const UnreadAboveIndicator = () => {
const isFirstUnreadAbove = useSelector(isFirstUnreadMessageIdAbove);
const firstUnreadMessageId = useSelector(getFirstUnreadMessageId) as string;
if (!isFirstUnreadAbove) {
return null;
}
return (
<SessionUnreadAboveIndicator key={`above-unread-indicator-${firstUnreadMessageId}`}>
{window.i18n('latestUnreadIsAbove')}
</SessionUnreadAboveIndicator>
);
};
type Props = SessionMessageListProps & { type Props = SessionMessageListProps & {
conversationKey?: string; conversationKey?: string;
messagesProps: Array<SortedMessageModelProps>; messagesProps: Array<SortedMessageModelProps>;
@ -139,6 +165,8 @@ class SessionMessagesListContainerInner extends React.Component<Props> {
onScroll={this.handleScroll} onScroll={this.handleScroll}
ref={this.props.messageContainerRef} ref={this.props.messageContainerRef}
> >
<UnreadAboveIndicator />
<TypingBubble <TypingBubble
pubkey={conversationKey} pubkey={conversationKey}
conversationType={conversation.type} conversationType={conversation.type}

@ -141,6 +141,22 @@ export const getHasOngoingCallWithPubkey = createSelector(
(withConvo: ReduxConversationType | undefined): string | undefined => withConvo?.id (withConvo: ReduxConversationType | undefined): string | undefined => withConvo?.id
); );
export const getHasOngoingCallWithFocusedConvo = createSelector(
getHasOngoingCallWithPubkey,
getSelectedConversationKey,
(withPubkey, selectedPubkey) => {
return withPubkey && withPubkey === selectedPubkey;
}
);
export const getHasOngoingCallWithNonFocusedConvo = createSelector(
getHasOngoingCallWithPubkey,
getSelectedConversationKey,
(withPubkey, selectedPubkey) => {
return withPubkey && withPubkey !== selectedPubkey;
}
);
export const getCallIsInFullScreen = createSelector( export const getCallIsInFullScreen = createSelector(
getConversations, getConversations,
(state: ConversationsStateType): boolean => state.callIsInFullScreen (state: ConversationsStateType): boolean => state.callIsInFullScreen

@ -4,6 +4,7 @@ import { SessionConversation } from '../../components/session/conversation/Sessi
import { StateType } from '../reducer'; import { StateType } from '../reducer';
import { getTheme } from '../selectors/theme'; import { getTheme } from '../selectors/theme';
import { import {
getHasOngoingCallWithFocusedConvo,
getLightBoxOptions, getLightBoxOptions,
getSelectedConversation, getSelectedConversation,
getSelectedConversationKey, getSelectedConversationKey,
@ -27,6 +28,7 @@ const mapStateToProps = (state: StateType) => {
selectedMessages: getSelectedMessageIds(state), selectedMessages: getSelectedMessageIds(state),
lightBoxOptions: getLightBoxOptions(state), lightBoxOptions: getLightBoxOptions(state),
stagedAttachments: getStagedAttachmentsForCurrentConversation(state), stagedAttachments: getStagedAttachmentsForCurrentConversation(state),
hasOngoingCallWithFocusedConvo: getHasOngoingCallWithFocusedConvo(state),
}; };
}; };

Loading…
Cancel
Save