@@ -1031,6 +1031,66 @@ Future<void> _uploadFiles({
10311031 }
10321032}
10331033
1034+ class _AttachVideoChatUrlButton extends StatelessWidget {
1035+ const _AttachVideoChatUrlButton ({
1036+ required this .controller,
1037+ required this .enabled,
1038+ });
1039+
1040+ final ComposeBoxController controller;
1041+ final bool enabled;
1042+
1043+ static const int jitsi = 1 ;
1044+ static const int zoom = 2 ;
1045+ static const int googleMeet = 5 ;
1046+
1047+ String _generateJitsiUrl (String serverUrl, String linkText) {
1048+ final id = List .generate (15 , (_) => Random .secure ().nextInt (10 )).join ();
1049+ return '[$linkText ]($serverUrl /$id #config.startWithVideoMuted=false)\n ' ;
1050+ }
1051+
1052+ String ? _getMeetingUrl (BuildContext context, int ? provider, String ? jitsiServerUrl) {
1053+ if (jitsiServerUrl == null ) return null ;
1054+
1055+ final linkText = ZulipLocalizations .of (context).composeBoxAttachFromVideoCallTooltip;
1056+
1057+ switch (provider) {
1058+ case jitsi: return _generateJitsiUrl (jitsiServerUrl, linkText);
1059+ case zoom: return 'https://zoom.us/start/meeting' ;
1060+ case googleMeet: return 'https://meet.google.com/new' ;
1061+ default : return null ;
1062+ }
1063+ }
1064+
1065+ void _handlePress (BuildContext context) {
1066+ final store = PerAccountStoreWidget .of (context);
1067+ final url = _getMeetingUrl (context, store.realmVideoChatProvider, store.realmJitsiServerUrl);
1068+
1069+ if (url == null ) return ;
1070+
1071+ final text = controller.content.text;
1072+ final selection = controller.content.selection;
1073+
1074+ controller
1075+ ..content.text = text.replaceRange (selection.start, selection.end, url)
1076+ ..content.selection = TextSelection .collapsed (
1077+ offset: selection.start + url.length);
1078+ }
1079+
1080+ @override
1081+ Widget build (BuildContext context) {
1082+ final designVariables = DesignVariables .of (context);
1083+ final zulipLocalizations = ZulipLocalizations .of (context);
1084+
1085+ return SizedBox (
1086+ width: _composeButtonSize,
1087+ child: IconButton (
1088+ icon: Icon (ZulipIcons .video, color: designVariables.foreground.withFadedAlpha (0.5 )),
1089+ tooltip: zulipLocalizations.composeBoxAttachFromVideoCallTooltip,
1090+ onPressed: enabled ? () => _handlePress (context) : null ));
1091+ }
1092+ }
1093+
10341094abstract class _AttachUploadsButton extends StatelessWidget {
10351095 const _AttachUploadsButton ({required this .controller, required this .enabled});
10361096
@@ -1469,6 +1529,7 @@ abstract class _ComposeBoxBody extends StatelessWidget {
14691529 _AttachFileButton (controller: controller, enabled: composeButtonsEnabled),
14701530 _AttachMediaButton (controller: controller, enabled: composeButtonsEnabled),
14711531 _AttachFromCameraButton (controller: controller, enabled: composeButtonsEnabled),
1532+ _AttachVideoChatUrlButton (controller: controller, enabled: composeButtonsEnabled),
14721533 ];
14731534
14741535 final topicInput = buildTopicInput ();
0 commit comments