Add call duration (#2059)

* add call duration once connected

* close incoming call dialog if endCall from same sender

* disable message request toggle if featureFlag is OFF
pull/2071/head
Audric Ackermann 3 years ago committed by GitHub
parent 1ec637b551
commit 1a699879cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -427,7 +427,7 @@
Whisper.Notifications.disable(); // avoid notification flood until empty
setTimeout(() => {
Whisper.Notifications.enable();
}, window.CONSTANTS.NOTIFICATION_ENABLE_TIMEOUT_SECONDS * 1000);
}, 10 * 1000); // 10 sec
window.NewReceiver.queueAllCached();
window.libsession.Utils.AttachmentDownloads.start({

@ -246,7 +246,7 @@ async function createWindow() {
minWidth,
minHeight,
autoHideMenuBar: false,
backgroundColor: '#fff',
backgroundColor: '#000',
webPreferences: {
nodeIntegration: false,
enableRemoteModule: true,
@ -535,7 +535,7 @@ function showAbout() {
resizable: false,
title: locale.messages.about,
autoHideMenuBar: true,
backgroundColor: '#ffffff',
backgroundColor: '#000',
show: false,
webPreferences: {
nodeIntegration: false,
@ -577,7 +577,7 @@ async function showDebugLogWindow() {
resizable: false,
title: locale.messages.debugLog,
autoHideMenuBar: true,
backgroundColor: '#FFFFFF',
backgroundColor: '#000',
show: false,
modal: true,
webPreferences: {

@ -55,12 +55,6 @@ window.isBeforeVersion = (toCheck, baseVersion) => {
}
};
// eslint-disable-next-line func-names
window.CONSTANTS = new (function() {
// Number of seconds to turn on notifications after reconnect/start of app
this.NOTIFICATION_ENABLE_TIMEOUT_SECONDS = 10;
})();
window.versionInfo = {
environment: window.getEnvironment(),
version: window.getVersion(),
@ -270,9 +264,7 @@ window.moment.updateLocale(localeSetForMoment, {
});
window.libsession = require('./ts/session');
window.models = require('./ts/models');
window.Signal = window.Signal || {};
window.Signal.Data = require('./ts/data/data');
window.Signal.Logs = require('./js/modules/logs');
@ -287,16 +279,6 @@ window.addEventListener('contextmenu', e => {
});
window.NewReceiver = require('./ts/receiver/receiver');
window.Fsv2 = require('./ts/fileserver/FileServerApiV2');
window.DataMessageReceiver = require('./ts/receiver/dataMessage');
window.NewSnodeAPI = require('./ts/session/snode_api/SNodeAPI');
window.SnodePool = require('./ts/session/snode_api/snodePool');
// eslint-disable-next-line no-extend-native,func-names
Promise.prototype.ignore = function() {
// eslint-disable-next-line more/no-then
this.then(() => {});
};
// Blocking

@ -55,7 +55,7 @@ export const Timestamp = (props: Props) => {
// Use relative time for under 24hrs ago.
const now = Math.floor(Date.now());
const messageAgeInDays = (now - timestamp) / (window.CONSTANTS.SECS_IN_DAY * 1000);
const messageAgeInDays = (now - timestamp) / (1000 * 60 * 60 * 24);
const daysBeforeRelativeTiming = 1;
let dateString;

@ -177,7 +177,7 @@ export class SessionClosableOverlay extends React.Component<Props, State> {
placeholder={placeholder}
value={groupName}
isGroup={true}
maxLength={window.CONSTANTS.MAX_GROUPNAME_LENGTH}
maxLength={100}
onChange={this.onGroupNameChanged}
onPressEnter={() => onButtonClick(groupName, selectedMembers)}
/>

@ -1,14 +1,15 @@
import React, { useRef } from 'react';
import { useSelector } from 'react-redux';
import React, { useRef, useState } from 'react';
import styled from 'styled-components';
import _ from 'underscore';
import { UserUtils } from '../../../session/utils';
import { CallManager, UserUtils } from '../../../session/utils';
import {
getCallIsInFullScreen,
getCallWithFocusedConvoIsOffering,
getCallWithFocusedConvosIsConnected,
getCallWithFocusedConvosIsConnecting,
getHasOngoingCallWithFocusedConvo,
getHasOngoingCallWithFocusedConvoIsOffering,
getHasOngoingCallWithFocusedConvosIsConnecting,
getHasOngoingCallWithPubkey,
} from '../../../state/selectors/call';
import { StyledVideoElement } from './DraggableCallContainer';
@ -19,11 +20,15 @@ import { useModuloWithTripleDots } from '../../../hooks/useModuloWithTripleDots'
import { CallWindowControls } from './CallButtons';
import { SessionSpinner } from '../SessionSpinner';
import { DEVICE_DISABLED_DEVICE_ID } from '../../../session/utils/calling/CallManager';
// tslint:disable-next-line: no-submodule-imports
import useInterval from 'react-use/lib/useInterval';
import moment from 'moment';
const VideoContainer = styled.div`
height: 100%;
width: 50%;
z-index: 0;
padding-top: 30px; // leave some space at the top for the connecting/duration of the current call
`;
const InConvoCallWindow = styled.div`
@ -66,10 +71,11 @@ const StyledCenteredLabel = styled.div`
white-space: nowrap;
color: white;
text-shadow: 0px 0px 8px white;
z-index: 5;
`;
const RingingLabel = () => {
const ongoingCallWithFocusedIsRinging = useSelector(getHasOngoingCallWithFocusedConvoIsOffering);
const ongoingCallWithFocusedIsRinging = useSelector(getCallWithFocusedConvoIsOffering);
const modulatedStr = useModuloWithTripleDots(window.i18n('ringing'), 3, 1000);
if (!ongoingCallWithFocusedIsRinging) {
@ -79,9 +85,7 @@ const RingingLabel = () => {
};
const ConnectingLabel = () => {
const ongoingCallWithFocusedIsConnecting = useSelector(
getHasOngoingCallWithFocusedConvosIsConnecting
);
const ongoingCallWithFocusedIsConnecting = useSelector(getCallWithFocusedConvosIsConnecting);
const modulatedStr = useModuloWithTripleDots(window.i18n('establishingConnection'), 3, 1000);
@ -92,6 +96,29 @@ const ConnectingLabel = () => {
return <StyledCenteredLabel>{modulatedStr}</StyledCenteredLabel>;
};
const DurationLabel = () => {
const [callDuration, setCallDuration] = useState<undefined | number>(undefined);
const ongoingCallWithFocusedIsConnected = useSelector(getCallWithFocusedConvosIsConnected);
useInterval(() => {
const duration = CallManager.getCurrentCallDuration();
if (duration) {
setCallDuration(duration);
}
}, 100);
if (!ongoingCallWithFocusedIsConnected || !callDuration || callDuration < 0) {
return null;
}
const ms = callDuration * 1000;
const d = moment.duration(ms);
// tslint:disable-next-line: restrict-plus-operands
const dateString = Math.floor(d.asHours()) + moment.utc(ms).format(':mm:ss');
return <StyledCenteredLabel>{dateString}</StyledCenteredLabel>;
};
const StyledSpinner = styled.div<{ fullWidth: boolean }>`
height: 100%;
width: ${props => (props.fullWidth ? '100%' : '50%')};
@ -167,6 +194,7 @@ export const InConversationCallContainer = () => {
<RelativeCallWindow>
<RingingLabel />
<ConnectingLabel />
<DurationLabel />
<VideoContainer>
<VideoLoadingSpinner fullWidth={false} />
<StyledVideoElement

@ -59,6 +59,8 @@ export const SettingsCategoryPrivacy = (props: {
const forceUpdate = useUpdate();
const dispatch = useDispatch();
const hasMessageRequestFlag = window.lokiFeatureFlags.useMessageRequests;
if (props.hasPassword !== null) {
return (
<>
@ -71,7 +73,6 @@ export const SettingsCategoryPrivacy = (props: {
description={window.i18n('mediaPermissionsDescription')}
active={Boolean(window.getSettingValue('media-permissions'))}
/>
{window.lokiFeatureFlags.useCallMessage && (
<SessionToggleWithDescription
onClickToggle={async () => {
@ -113,14 +114,16 @@ export const SettingsCategoryPrivacy = (props: {
description={window.i18n('autoUpdateSettingDescription')}
active={Boolean(window.getSettingValue(settingsAutoUpdate))}
/>
<SessionToggleWithDescription
onClickToggle={() => {
dispatch(toggleMessageRequests());
}}
title={window.i18n('messageRequests')}
description={window.i18n('messageRequestsDescription')}
active={useSelector(getIsMessageRequestsEnabled)}
/>
{hasMessageRequestFlag && (
<SessionToggleWithDescription
onClickToggle={() => {
dispatch(toggleMessageRequests());
}}
title={window.i18n('messageRequests')}
description={window.i18n('messageRequestsDescription')}
active={useSelector(getIsMessageRequestsEnabled)}
/>
)}
{!props.hasPassword && (
<SessionSettingButtonItem
title={window.i18n('setAccountPasswordTitle')}

@ -37,6 +37,8 @@ export const callTimeoutMs = 30000;
*/
let currentCallUUID: string | undefined;
let currentCallStartTimestamp: number | undefined;
const rejectedCallUUIDS: Set<string> = new Set();
export type CallManagerOptionsType = {
@ -591,12 +593,16 @@ function handleConnectionStateChanged(pubkey: string) {
if (firstAudioOutput) {
void selectAudioOutputByDeviceId(firstAudioOutput);
}
currentCallStartTimestamp = Date.now();
window.inboxStore?.dispatch(callConnected({ pubkey }));
}
}
function closeVideoCall() {
window.log.info('closingVideoCall ');
currentCallStartTimestamp = undefined;
setIsRinging(false);
if (peerConnection) {
peerConnection.ontrack = null;
@ -909,13 +915,13 @@ export async function handleCallTypeEndCall(sender: string, aboutCallUUID?: stri
if (aboutCallUUID) {
rejectedCallUUIDS.add(aboutCallUUID);
const { ongoingCallStatus, ongoingCallWith } = getCallingStateOutsideOfRedux();
clearCallCacheFromPubkeyAndUUID(sender, aboutCallUUID);
// this is a end call from ourself. We must remove the popup about the incoming call
// if it matches the owner of this callUUID
if (sender === UserUtils.getOurPubKeyStrFromCache()) {
const { ongoingCallStatus, ongoingCallWith } = getCallingStateOutsideOfRedux();
const ownerOfCall = getOwnerOfCallUUID(aboutCallUUID);
if (
@ -928,8 +934,17 @@ export async function handleCallTypeEndCall(sender: string, aboutCallUUID?: stri
return;
}
// remote user hangup while we were on the call with him
if (aboutCallUUID === currentCallUUID) {
closeVideoCall();
window.inboxStore?.dispatch(endCall());
} else if (
ongoingCallWith === sender &&
(ongoingCallStatus === 'incoming' || ongoingCallStatus === 'connecting')
) {
// remote user hangup an offer he sent but we did not accept it yet
setIsRinging(false);
window.inboxStore?.dispatch(endCall());
}
}
@ -1295,8 +1310,15 @@ export function onTurnedOnCallMediaPermissions() {
Date.now() - msg.timestamp < DURATION.MINUTES * 1
) {
window.inboxStore?.dispatch(incomingCall({ pubkey: key }));
break;
}
}
});
});
}
export function getCurrentCallDuration() {
return currentCallStartTimestamp
? Math.floor((Date.now() - currentCallStartTimestamp) / 1000)
: undefined;
}

@ -1,5 +1,5 @@
import { createSelector } from 'reselect';
import { CallStateType } from '../ducks/call';
import { CallStateType, CallStatusEnum } from '../ducks/call';
import { ConversationsStateType, ReduxConversationType } from '../ducks/conversations';
import { StateType } from '../reducer';
import { getConversations, getSelectedConversationKey } from './conversations';
@ -55,37 +55,40 @@ export const getHasOngoingCallWithFocusedConvo = createSelector(
}
);
export const getHasOngoingCallWithFocusedConvoIsOffering = createSelector(
const getCallStateWithFocusedConvo = createSelector(
getCallState,
getSelectedConversationKey,
(callState: CallStateType, selectedConvoPubkey?: string): boolean => {
(callState: CallStateType, selectedConvoPubkey?: string): CallStatusEnum => {
if (
!selectedConvoPubkey ||
!callState.ongoingWith ||
callState.ongoingCallStatus !== 'offering' ||
selectedConvoPubkey !== callState.ongoingWith
selectedConvoPubkey &&
callState.ongoingWith &&
selectedConvoPubkey === callState.ongoingWith
) {
return false;
return callState.ongoingCallStatus;
}
return true;
return undefined;
}
);
export const getHasOngoingCallWithFocusedConvosIsConnecting = createSelector(
getCallState,
getSelectedConversationKey,
(callState: CallStateType, selectedConvoPubkey?: string): boolean => {
if (
!selectedConvoPubkey ||
!callState.ongoingWith ||
callState.ongoingCallStatus !== 'connecting' ||
selectedConvoPubkey !== callState.ongoingWith
) {
return false;
}
export const getCallWithFocusedConvoIsOffering = createSelector(
getCallStateWithFocusedConvo,
(callState: CallStatusEnum): boolean => {
return callState === 'offering';
}
);
export const getCallWithFocusedConvosIsConnecting = createSelector(
getCallStateWithFocusedConvo,
(callState: CallStatusEnum): boolean => {
return callState === 'connecting';
}
);
return true;
export const getCallWithFocusedConvosIsConnected = createSelector(
getCallStateWithFocusedConvo,
(callState: CallStatusEnum): boolean => {
return callState === 'ongoing';
}
);

Loading…
Cancel
Save