Skip to content

Commit b351456

Browse files
committed
feat: click on call message to open call window
So far only when the call state is "alerting". This is useful for when the caller is not among "who can call me" (#6044). Partially addresses #6081.
1 parent fbfc79b commit b351456

File tree

7 files changed

+96
-10
lines changed

7 files changed

+96
-10
lines changed

packages/frontend/src/components/message/Message.tsx

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import React, {
33
useCallback,
44
useContext,
55
useEffect,
6+
useEffectEvent,
67
useMemo,
78
useRef,
89
useState,
@@ -65,7 +66,8 @@ import { mouseEventToPosition } from '../../utils/mouseEventToPosition'
6566
import { useRovingTabindex } from '../../contexts/RovingTabindex'
6667
import { avatarInitial } from '@deltachat-desktop/shared/avatarInitial'
6768
import { getLogger } from '@deltachat-desktop/shared/logger'
68-
import Icon from '../Icon'
69+
import { IconButton } from '../Icon'
70+
import { useRpcFetch } from '../../hooks/useFetch'
6971

7072
const log = getLogger('Message')
7173

@@ -817,12 +819,10 @@ export default function Message(props: {
817819
/>
818820
) : null}
819821
{message.viewType === 'Call' && (
820-
<Icon
821-
icon='phone'
822-
className='phone-icon'
823-
coloring='currentColor'
824-
// `size` will be overridden in CSS
825-
size={24}
822+
<CallIconButton
823+
accountId={accountId}
824+
chatId={message.chatId}
825+
messageId={message.id}
826826
/>
827827
)}
828828
</div>
@@ -1249,3 +1249,60 @@ function WebxdcMessageContent({
12491249
</div>
12501250
)
12511251
}
1252+
1253+
function CallIconButton({
1254+
accountId,
1255+
chatId,
1256+
messageId,
1257+
}: {
1258+
accountId: number
1259+
chatId: number
1260+
messageId: number
1261+
}) {
1262+
const callInfoFetch = useRpcFetch(BackendRemote.rpc.callInfo, [
1263+
accountId,
1264+
messageId,
1265+
])
1266+
const refresh = useEffectEvent(callInfoFetch.refresh)
1267+
useEffect(() => {
1268+
return onDCEvent(accountId, 'MsgsChanged', event => {
1269+
if (event.msgId !== messageId) {
1270+
return
1271+
}
1272+
refresh()
1273+
})
1274+
}, [accountId, messageId])
1275+
1276+
const onClickParams:
1277+
| undefined
1278+
| Parameters<typeof runtime.openIncomingVideoCallWindow>[0] =
1279+
callInfoFetch.result?.ok &&
1280+
callInfoFetch.result.value.state.kind === 'Alerting'
1281+
? {
1282+
accountId,
1283+
chatId,
1284+
callMessageId: messageId,
1285+
callerWebrtcOffer: callInfoFetch.result.value.sdpOffer,
1286+
startWithCameraEnabled: callInfoFetch.result.value.hasVideo,
1287+
}
1288+
: undefined
1289+
// TODO fix: don't open a second window if one is already open
1290+
// for this message (this should be done in the main process).
1291+
const onClick = onClickParams
1292+
? () => runtime.openIncomingVideoCallWindow(onClickParams)
1293+
: undefined
1294+
1295+
return (
1296+
<IconButton
1297+
aria-label='📞'
1298+
onClick={onClick}
1299+
aria-busy={callInfoFetch.loading}
1300+
disabled={onClick == undefined}
1301+
icon='phone'
1302+
className='phone-icon'
1303+
coloring='currentColor'
1304+
// `size` will be overridden in CSS
1305+
size={24}
1306+
/>
1307+
)
1308+
}

packages/runtime/runtime.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,13 @@ export interface Runtime {
138138
chatId: number,
139139
param: { startWithCameraEnabled: boolean }
140140
): void
141+
openIncomingVideoCallWindow(params: {
142+
accountId: number
143+
chatId: number
144+
callMessageId: number
145+
callerWebrtcOffer: string
146+
startWithCameraEnabled: boolean
147+
}): Promise<void>
141148

142149
// control app
143150
restartApp(): void

packages/target-browser/runtime-browser/runtime.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ class BrowserRuntime implements Runtime {
207207
startOutgoingVideoCall(): void {
208208
this.log.critical('Method not implemented.')
209209
}
210+
async openIncomingVideoCallWindow() {
211+
throw new Error('Method not implemented.')
212+
}
210213
async saveBackgroundImage(
211214
file: string,
212215
isDefaultPicture: boolean

packages/target-electron/runtime-electron/runtime.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,15 @@ class ElectronRuntime implements Runtime {
208208
): Promise<void> {
209209
return ipcBackend.invoke('startOutgoingVideoCall', accountId, chatId, param)
210210
}
211+
openIncomingVideoCallWindow(params: {
212+
accountId: number
213+
chatId: number
214+
callMessageId: number
215+
callerWebrtcOffer: string
216+
startWithCameraEnabled: boolean
217+
}): Promise<void> {
218+
return ipcBackend.invoke('openIncomingVideoCallWindow', params)
219+
}
211220
openMapsWebxdc(accountId: number, chatId?: number | undefined): void {
212221
ipcBackend.invoke('open-maps-webxdc', accountId, chatId)
213222
}

packages/target-electron/src/ipc.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,11 @@ import { appx, mapPackagePath } from './isAppx.js'
4444
import DeltaChatController from './deltachat/controller.js'
4545
import { BuildInfo } from './get-build-info.js'
4646
import { updateContentProtectionOnAllActiveWindows } from './content-protection.js'
47-
import { MediaType } from '@deltachat-desktop/runtime-interface'
47+
import { MediaType, type Runtime } from '@deltachat-desktop/runtime-interface'
4848
import {
4949
startHandlingIncomingVideoCalls,
5050
startOutgoingVideoCall,
51+
openIncomingVideoCallWindow,
5152
} from './windows/video-call.js'
5253

5354
const __dirname = dirname(fileURLToPath(import.meta.url))
@@ -402,6 +403,12 @@ export async function init(cwd: string, logHandler: LogHandler) {
402403
startOutgoingVideoCall(accountId, chatId, param)
403404
}
404405
)
406+
ipcMain.handle(
407+
'openIncomingVideoCallWindow',
408+
(_ev, ...args: Parameters<Runtime['openIncomingVideoCallWindow']>) => {
409+
openIncomingVideoCallWindow(...args)
410+
}
411+
)
405412
const stopHandlingIncomingVideoCalls = startHandlingIncomingVideoCalls(
406413
dcController.jsonrpcRemote
407414
)

packages/target-electron/src/windows/video-call.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ export function startHandlingIncomingVideoCalls(
117117
return () => jsonrpcRemote.off('IncomingCall', incomingCallListener)
118118
}
119119

120-
function openIncomingVideoCallWindow({
120+
export function openIncomingVideoCallWindow({
121121
accountId,
122122
chatId,
123123
callMessageId,
@@ -130,7 +130,7 @@ function openIncomingVideoCallWindow({
130130
callerWebrtcOffer: string
131131
startWithCameraEnabled: boolean
132132
}) {
133-
log.info('received incoming call', {
133+
log.info('openIncomingVideoCallWindow', {
134134
accountId,
135135
chatId,
136136
callMessageId,

packages/target-tauri/runtime-tauri/runtime.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,9 @@ class TauriRuntime implements Runtime {
553553
startOutgoingVideoCall(): void {
554554
throw new Error('Method not implemented.101')
555555
}
556+
async openIncomingVideoCallWindow() {
557+
throw new Error('Method not implemented.102')
558+
}
556559
restartApp(): void {
557560
// will not be implemented in tauri for now, as this method is currently unused
558561
this.log.error('Method not implemented: restartApp')

0 commit comments

Comments
 (0)