Skip to content

Commit 5cdefc7

Browse files
committed
AttachmentSources: live streams support
1 parent c1bdb1f commit 5cdefc7

File tree

1 file changed

+82
-9
lines changed

1 file changed

+82
-9
lines changed

src/common/attachment-drafts/attachment-sources/AttachmentSources.tsx

Lines changed: 82 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ import * as React from 'react';
22
import { keyframes } from '@emotion/react';
33
import type { FileWithHandle } from 'browser-fs-access';
44

5-
import { Box, Button, Checkbox, ColorPaletteProp, Divider, Dropdown, IconButton, ListItem, ListItemDecorator, Menu, MenuButton, MenuItem } from '@mui/joy';
5+
import { Box, Button, Checkbox, ColorPaletteProp, Dropdown, IconButton, ListDivider, ListItem, ListItemDecorator, Menu, MenuButton, MenuItem } from '@mui/joy';
66
import AddRoundedIcon from '@mui/icons-material/AddRounded';
77
import AddToDriveRoundedIcon from '@mui/icons-material/AddToDriveRounded';
88
import AttachFileRoundedIcon from '@mui/icons-material/AttachFileRounded';
99
import CameraAltOutlinedIcon from '@mui/icons-material/CameraAltOutlined';
1010
import ContentPasteGoIcon from '@mui/icons-material/ContentPasteGo';
11+
import FiberManualRecordIcon from '@mui/icons-material/FiberManualRecord';
1112
import LanguageRoundedIcon from '@mui/icons-material/LanguageRounded';
1213
import ScreenshotMonitorIcon from '@mui/icons-material/ScreenshotMonitor';
1314

@@ -35,10 +36,11 @@ const animationMenuItem = keyframes` from {opacity: 0;transform: translateY(-6px
3536

3637
const _style = {
3738
menuItem: {
38-
py: 1,
3939
// pl: 3,
4040
// pr: 2,
41+
py: 0.5, // was 1
4142
minHeight: 60,
43+
// minHeight: '3.25rem', // now 52, was 60
4244
} as const,
4345
menuItemContent: {
4446
display: 'flex',
@@ -58,6 +60,24 @@ const _style = {
5860
};
5961

6062

63+
// Live feed record button - returns null if onClick is undefined
64+
function LiveFeedButton(props: { isActive: boolean, onClick: () => void }) {
65+
return (
66+
<IconButton
67+
size='sm'
68+
variant={props.isActive ? 'solid' : 'soft'}
69+
color='danger'
70+
onClick={(e) => {
71+
e.stopPropagation();
72+
props.onClick();
73+
}}
74+
>
75+
<FiberManualRecordIcon sx={{ fontSize: 16 }} />
76+
</IconButton>
77+
);
78+
}
79+
80+
6181
// Rich menu item (used in menu-rich mode)
6282
function RichMenuItem(props: {
6383
name: React.ReactNode;
@@ -67,6 +87,7 @@ function RichMenuItem(props: {
6787
delay?: number;
6888
disabled?: boolean;
6989
color?: ColorPaletteProp;
90+
endAction?: React.ReactNode;
7091
}) {
7192
return (
7293
<MenuItem
@@ -89,6 +110,11 @@ function RichMenuItem(props: {
89110
{props.description}
90111
</Box>
91112
</Box>
113+
{props.endAction && (
114+
<Box sx={{ ml: 'auto', display: 'flex', alignItems: 'center' }}>
115+
{props.endAction}
116+
</Box>
117+
)}
92118
</MenuItem>
93119
);
94120
}
@@ -107,7 +133,7 @@ function AutoDownloadToggle(props: { delay?: number }) {
107133

108134
return <>
109135

110-
<Divider sx={{ my: 0.5 }} />
136+
<ListDivider inset='gutter' sx={{ my: 1 }} />
111137

112138
<ListItem
113139
sx={{
@@ -165,6 +191,11 @@ function AttachmentSources(props: {
165191
hasScreenCapture: boolean,
166192
// configuration
167193
onlyImages?: boolean, // makes clipboard/drive/web unavailable
194+
// live feeds - end action buttons (presence if the callback is set, active state if the boolean is true)
195+
hasActiveCameraFeed?: boolean,
196+
hasActiveScreenFeed?: boolean,
197+
onStartLiveCameraFeed?: () => void,
198+
onStartLiveScreenFeed?: () => void,
168199
// callbacks
169200
onAttachClipboard: () => void,
170201
onAttachFiles: (files: FileWithHandle[], errorMessage: string | null) => void,
@@ -299,7 +330,15 @@ function AttachmentSources(props: {
299330
// <ListItemDecorator><ScreenshotMonitorIcon /></ListItemDecorator>
300331
// Screen
301332
// </MenuItem>
302-
<RichMenuItem name='Screen' description={screenCaptureError ? `Error: ${screenCaptureError}` : 'Capture windows, tabs, or screens'} color={screenCaptureError ? 'danger' : props.color} icon={<ScreenshotMonitorIcon />} onClick={handleTakeScreenCapture} disabled={capturingScreen} />
333+
<RichMenuItem
334+
name='Screen'
335+
color={screenCaptureError ? 'danger' : props.color}
336+
description={screenCaptureError ? `Error: ${screenCaptureError}` : 'Capture tabs, apps, and screens'}
337+
icon={<ScreenshotMonitorIcon />}
338+
disabled={capturingScreen}
339+
onClick={handleTakeScreenCapture}
340+
endAction={!isMessage && props.onStartLiveScreenFeed && <LiveFeedButton isActive={!!props.hasActiveScreenFeed} onClick={props.onStartLiveScreenFeed} />}
341+
/>
303342
)}
304343

305344
{/* Camera */}
@@ -308,7 +347,14 @@ function AttachmentSources(props: {
308347
// <ListItemDecorator><CameraAltOutlinedIcon /></ListItemDecorator>
309348
// Camera
310349
// </MenuItem>
311-
<RichMenuItem name='Camera' description='Capture photos and optional OCR' color={props.color} icon={<CameraAltOutlinedIcon />} onClick={props.onOpenCamera} />
350+
<RichMenuItem
351+
name='Camera'
352+
color={props.color}
353+
icon={<CameraAltOutlinedIcon />}
354+
description='Capture photos with optional OCR'
355+
onClick={props.onOpenCamera}
356+
endAction={!isMessage && props.onStartLiveCameraFeed && <LiveFeedButton isActive={!!props.hasActiveCameraFeed} onClick={props.onStartLiveCameraFeed} />}
357+
/>
312358
)}
313359

314360
</Menu>
@@ -412,25 +458,51 @@ function AttachmentSources(props: {
412458
<RichMenuItem
413459
name='Clipboard'
414460
icon={<ContentPasteGoIcon />}
415-
description='Auto-converts images and text to the best format'
461+
// description='Auto-converts images and text to the best format'
462+
description='Auto-adapts images and text'
416463
onClick={props.onAttachClipboard}
417464
delay={0.06}
418465
/>
419466
)}
420467

468+
{/*{!props.onlyImages && props.canBrowse && (*/}
469+
{/* <ListItem>*/}
470+
{/* <ListItemDecorator />*/}
471+
{/* <Checkbox*/}
472+
{/* size='sm'*/}
473+
{/* color='neutral'*/}
474+
{/* // checked={enableComposerAttach}*/}
475+
{/* // onChange={handleToggle}*/}
476+
{/* onClick={(event) => event.stopPropagation()}*/}
477+
{/* sx={{ ml: 0.375 }}*/}
478+
{/* slotProps={{*/}
479+
{/* label: {*/}
480+
{/* sx: {*/}
481+
{/* fontSize: 'sm',*/}
482+
{/* fontWeight: 'md',*/}
483+
{/* },*/}
484+
{/* },*/}
485+
{/* }}*/}
486+
{/* label='Download and attach links'*/}
487+
{/* />*/}
488+
{/* </ListItem>*/}
489+
{/*)}*/}
490+
491+
421492
{/* Divider before labs features */}
422-
{(props.hasScreenCapture || props.hasCamera) && <Divider sx={{ my: 0.5 }} />}
493+
{(props.hasScreenCapture || props.hasCamera) && <ListDivider inset='gutter' sx={{ my: 1 }} />}
423494

424495
{/* Screen Capture */}
425496
{props.hasScreenCapture && (
426497
<RichMenuItem
427498
name='Screen'
428499
icon={<ScreenshotMonitorIcon />}
429-
description={screenCaptureError ? `Error: ${screenCaptureError}` : 'Capture windows, tabs, or screens'}
500+
description={screenCaptureError ? `Error: ${screenCaptureError}` : 'Capture tabs, apps, and screens'}
430501
onClick={handleTakeScreenCapture}
431502
disabled={capturingScreen}
432503
color={screenCaptureError ? 'danger' : undefined}
433504
delay={0.08}
505+
endAction={props.onStartLiveScreenFeed && <LiveFeedButton isActive={!!props.hasActiveScreenFeed} onClick={props.onStartLiveScreenFeed} />}
434506
/>
435507
)}
436508

@@ -439,9 +511,10 @@ function AttachmentSources(props: {
439511
<RichMenuItem
440512
name='Camera'
441513
icon={<CameraAltOutlinedIcon />}
442-
description='Capture photos with optional text recognition'
514+
description='Capture photos with optional OCR'
443515
onClick={props.onOpenCamera}
444516
delay={0.1}
517+
endAction={props.onStartLiveCameraFeed && <LiveFeedButton isActive={!!props.hasActiveCameraFeed} onClick={props.onStartLiveCameraFeed} />}
445518
/>
446519
)}
447520

0 commit comments

Comments
 (0)