Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ android {
namespace "com.zulip.flutter"

compileSdkVersion flutter.compileSdkVersion
ndkVersion "28.2.13676358"

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
Expand Down
Binary file modified assets/icons/ZulipIcons.ttf
Binary file not shown.
1 change: 1 addition & 0 deletions assets/icons/video.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions assets/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,10 @@
"@composeBoxAttachFromCameraTooltip": {
"description": "Tooltip for compose box icon to attach an image from the camera to the message."
},
"composeBoxAttachFromVideoCallTooltip": "Join video call.",
"@composeBoxAttachFromVideoCallTooltip": {
"description": "Tooltip for compose box icon to attach a video call url from the jitsi to the message."
},
"composeBoxGenericContentHint": "Type a message",
"@composeBoxGenericContentHint": {
"description": "Hint text for content input when sending a message."
Expand Down
6 changes: 6 additions & 0 deletions lib/api/model/initial_snapshot.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ class InitialSnapshot {
/// Search for "realm_wildcard_mention_policy" in https://zulip.com/api/register-queue.
final RealmWildcardMentionPolicy realmWildcardMentionPolicy;

final int realmVideoChatProvider;

final bool realmMandatoryTopics;

final String realmName;
Expand All @@ -113,6 +115,8 @@ class InitialSnapshot {

final Map<String, RealmDefaultExternalAccount> realmDefaultExternalAccounts;

final String? jitsiServerUrl;

final int maxFileUploadSizeMib;

final Uri serverEmojiDataUrl;
Expand Down Expand Up @@ -181,6 +185,7 @@ class InitialSnapshot {
required this.realmDeleteOwnMessagePolicy,
required this.realmWildcardMentionPolicy,
required this.realmMandatoryTopics,
required this.realmVideoChatProvider,
required this.realmName,
required this.realmWaitingPeriodThreshold,
required this.realmMessageContentDeleteLimitSeconds,
Expand All @@ -190,6 +195,7 @@ class InitialSnapshot {
required this.realmIconUrl,
required this.realmPresenceDisabled,
required this.realmDefaultExternalAccounts,
required this.jitsiServerUrl,
required this.maxFileUploadSizeMib,
required this.serverEmojiDataUrl,
required this.realmEmptyTopicDisplayName,
Expand Down
4 changes: 4 additions & 0 deletions lib/api/model/initial_snapshot.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions lib/generated/l10n/zulip_localizations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,12 @@ abstract class ZulipLocalizations {
/// **'Take a photo'**
String get composeBoxAttachFromCameraTooltip;

/// Tooltip for compose box icon to attach a video call url from the jitsi to the message.
///
/// In en, this message translates to:
/// **'Join video call.'**
String get composeBoxAttachFromVideoCallTooltip;

/// Hint text for content input when sending a message.
///
/// In en, this message translates to:
Expand Down
3 changes: 3 additions & 0 deletions lib/generated/l10n/zulip_localizations_ar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,9 @@ class ZulipLocalizationsAr extends ZulipLocalizations {
@override
String get composeBoxAttachFromCameraTooltip => 'Take a photo';

@override
String get composeBoxAttachFromVideoCallTooltip => 'Join video call.';

@override
String get composeBoxGenericContentHint => 'Type a message';

Expand Down
3 changes: 3 additions & 0 deletions lib/generated/l10n/zulip_localizations_de.dart
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,9 @@ class ZulipLocalizationsDe extends ZulipLocalizations {
@override
String get composeBoxAttachFromCameraTooltip => 'Ein Foto aufnehmen';

@override
String get composeBoxAttachFromVideoCallTooltip => 'Join video call.';

@override
String get composeBoxGenericContentHint => 'Eine Nachricht eingeben';

Expand Down
3 changes: 3 additions & 0 deletions lib/generated/l10n/zulip_localizations_en.dart
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,9 @@ class ZulipLocalizationsEn extends ZulipLocalizations {
@override
String get composeBoxAttachFromCameraTooltip => 'Take a photo';

@override
String get composeBoxAttachFromVideoCallTooltip => 'Join video call.';

@override
String get composeBoxGenericContentHint => 'Type a message';

Expand Down
3 changes: 3 additions & 0 deletions lib/generated/l10n/zulip_localizations_fr.dart
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,9 @@ class ZulipLocalizationsFr extends ZulipLocalizations {
@override
String get composeBoxAttachFromCameraTooltip => 'Take a photo';

@override
String get composeBoxAttachFromVideoCallTooltip => 'Join video call.';

@override
String get composeBoxGenericContentHint => 'Type a message';

Expand Down
3 changes: 3 additions & 0 deletions lib/generated/l10n/zulip_localizations_it.dart
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,9 @@ class ZulipLocalizationsIt extends ZulipLocalizations {
@override
String get composeBoxAttachFromCameraTooltip => 'Fai una foto';

@override
String get composeBoxAttachFromVideoCallTooltip => 'Join video call.';

@override
String get composeBoxGenericContentHint => 'Batti un messaggio';

Expand Down
3 changes: 3 additions & 0 deletions lib/generated/l10n/zulip_localizations_ja.dart
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,9 @@ class ZulipLocalizationsJa extends ZulipLocalizations {
@override
String get composeBoxAttachFromCameraTooltip => '写真を撮る';

@override
String get composeBoxAttachFromVideoCallTooltip => 'Join video call.';

@override
String get composeBoxGenericContentHint => 'メッセージを入力';

Expand Down
3 changes: 3 additions & 0 deletions lib/generated/l10n/zulip_localizations_nb.dart
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,9 @@ class ZulipLocalizationsNb extends ZulipLocalizations {
@override
String get composeBoxAttachFromCameraTooltip => 'Take a photo';

@override
String get composeBoxAttachFromVideoCallTooltip => 'Join video call.';

@override
String get composeBoxGenericContentHint => 'Type a message';

Expand Down
3 changes: 3 additions & 0 deletions lib/generated/l10n/zulip_localizations_pl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,9 @@ class ZulipLocalizationsPl extends ZulipLocalizations {
@override
String get composeBoxAttachFromCameraTooltip => 'Zrób zdjęcie';

@override
String get composeBoxAttachFromVideoCallTooltip => 'Join video call.';

@override
String get composeBoxGenericContentHint => 'Wpisz wiadomość';

Expand Down
3 changes: 3 additions & 0 deletions lib/generated/l10n/zulip_localizations_ru.dart
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,9 @@ class ZulipLocalizationsRu extends ZulipLocalizations {
@override
String get composeBoxAttachFromCameraTooltip => 'Сделать снимок';

@override
String get composeBoxAttachFromVideoCallTooltip => 'Join video call.';

@override
String get composeBoxGenericContentHint => 'Ввести сообщение';

Expand Down
3 changes: 3 additions & 0 deletions lib/generated/l10n/zulip_localizations_sk.dart
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,9 @@ class ZulipLocalizationsSk extends ZulipLocalizations {
@override
String get composeBoxAttachFromCameraTooltip => 'Take a photo';

@override
String get composeBoxAttachFromVideoCallTooltip => 'Join video call.';

@override
String get composeBoxGenericContentHint => 'Type a message';

Expand Down
3 changes: 3 additions & 0 deletions lib/generated/l10n/zulip_localizations_sl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,9 @@ class ZulipLocalizationsSl extends ZulipLocalizations {
@override
String get composeBoxAttachFromCameraTooltip => 'Fotografiraj';

@override
String get composeBoxAttachFromVideoCallTooltip => 'Join video call.';

@override
String get composeBoxGenericContentHint => 'Vnesite sporočilo';

Expand Down
3 changes: 3 additions & 0 deletions lib/generated/l10n/zulip_localizations_uk.dart
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,9 @@ class ZulipLocalizationsUk extends ZulipLocalizations {
@override
String get composeBoxAttachFromCameraTooltip => 'Зробити фото';

@override
String get composeBoxAttachFromVideoCallTooltip => 'Join video call.';

@override
String get composeBoxGenericContentHint => 'Ввести повідомлення';

Expand Down
3 changes: 3 additions & 0 deletions lib/generated/l10n/zulip_localizations_zh.dart
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,9 @@ class ZulipLocalizationsZh extends ZulipLocalizations {
@override
String get composeBoxAttachFromCameraTooltip => 'Take a photo';

@override
String get composeBoxAttachFromVideoCallTooltip => 'Join video call.';

@override
String get composeBoxGenericContentHint => 'Type a message';

Expand Down
12 changes: 12 additions & 0 deletions lib/model/realm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ mixin RealmStore on PerAccountStoreBase, UserGroupStore {
Duration get serverTypingStartedWaitPeriod => Duration(milliseconds: serverTypingStartedWaitPeriodMilliseconds);
int get serverTypingStartedWaitPeriodMilliseconds;

String? get jitsiServerUrl;
int get realmVideoChatProvider;
//|//////////////////////////////////////////////////////////////
// Realm settings.

Expand Down Expand Up @@ -174,6 +176,10 @@ mixin ProxyRealmStore on RealmStore {
@override
bool get realmMandatoryTopics => realmStore.realmMandatoryTopics;
@override
int get realmVideoChatProvider => realmStore.realmVideoChatProvider;
@override
String? get jitsiServerUrl => realmStore.jitsiServerUrl;
@override
int get maxFileUploadSizeMib => realmStore.maxFileUploadSizeMib;
@override
int? get realmMessageContentDeleteLimitSeconds => realmStore.realmMessageContentDeleteLimitSeconds;
Expand Down Expand Up @@ -230,6 +236,8 @@ class RealmStoreImpl extends HasUserGroupStore with RealmStore {
realmCanDeleteAnyMessageGroup = initialSnapshot.realmCanDeleteAnyMessageGroup,
realmCanDeleteOwnMessageGroup = initialSnapshot.realmCanDeleteOwnMessageGroup,
realmMandatoryTopics = initialSnapshot.realmMandatoryTopics,
realmVideoChatProvider = initialSnapshot.realmVideoChatProvider,
jitsiServerUrl = initialSnapshot.jitsiServerUrl,
maxFileUploadSizeMib = initialSnapshot.maxFileUploadSizeMib,
realmMessageContentDeleteLimitSeconds = initialSnapshot.realmMessageContentDeleteLimitSeconds,
realmMessageContentEditLimitSeconds = initialSnapshot.realmMessageContentEditLimitSeconds,
Expand Down Expand Up @@ -380,6 +388,10 @@ class RealmStoreImpl extends HasUserGroupStore with RealmStore {
@override
final bool realmMandatoryTopics;
@override
final int realmVideoChatProvider;
@override
final String? jitsiServerUrl;
@override
final int maxFileUploadSizeMib;
@override
final int? realmMessageContentDeleteLimitSeconds;
Expand Down
56 changes: 56 additions & 0 deletions lib/widgets/compose_box.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1031,6 +1031,61 @@ Future<void> _uploadFiles({
}
}

class _AttachVideoChatUrlButton extends StatelessWidget {
const _AttachVideoChatUrlButton({
required this.controller,
required this.enabled,
});

final ComposeBoxController controller;
final bool enabled;

static const int jitsi = 1;
static const int zoom = 2; //TODO: Add other supported video chat providers

String _generateJitsiUrl(String serverUrl, String linkText) {
final id = List.generate(15, (_) => Random.secure().nextInt(10)).join();
return '[$linkText]($serverUrl/$id#config.startWithVideoMuted=false)\n';
}

String? _getMeetingUrl(BuildContext context, int? provider, String? jitsiServerUrl) {
final linkText = ZulipLocalizations.of(context).composeBoxAttachFromVideoCallTooltip;

switch (provider) {
case jitsi: return jitsiServerUrl == null ? null :_generateJitsiUrl(jitsiServerUrl, linkText);
case zoom: return '[$linkText](https://zoom.us/start/meeting)';
default: return null;
}
}

void _handlePress(BuildContext context) {
final store = PerAccountStoreWidget.of(context);
final url = _getMeetingUrl(context, store.realmVideoChatProvider, store.jitsiServerUrl);
if (url == null) return;

final contentController = controller.content;
final insertionRange = contentController.insertionIndex();

contentController.value = contentController.value.replaced(insertionRange, url);
contentController.selection = TextSelection.collapsed(
offset: insertionRange.start + url.length);
controller.contentFocusNode.requestFocus();
}

@override
Widget build(BuildContext context) {
final designVariables = DesignVariables.of(context);
final zulipLocalizations = ZulipLocalizations.of(context);

return SizedBox(
width: _composeButtonSize,
child: IconButton(
icon: Icon(ZulipIcons.video, color: designVariables.foreground.withFadedAlpha(0.5)),
tooltip: zulipLocalizations.composeBoxAttachFromVideoCallTooltip,
onPressed: enabled ? () => _handlePress(context) : null));
}
}

abstract class _AttachUploadsButton extends StatelessWidget {
const _AttachUploadsButton({required this.controller, required this.enabled});

Expand Down Expand Up @@ -1469,6 +1524,7 @@ abstract class _ComposeBoxBody extends StatelessWidget {
_AttachFileButton(controller: controller, enabled: composeButtonsEnabled),
_AttachMediaButton(controller: controller, enabled: composeButtonsEnabled),
_AttachFromCameraButton(controller: controller, enabled: composeButtonsEnabled),
_AttachVideoChatUrlButton(controller: controller, enabled: composeButtonsEnabled),
];

final topicInput = buildTopicInput();
Expand Down
4 changes: 4 additions & 0 deletions lib/widgets/icons.dart
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,10 @@ abstract final class ZulipIcons {
/// The Zulip custom icon "unmute".
static const IconData unmute = IconData(0xf13a, fontFamily: "Zulip Icons");

/// The Zulip custom icon "video".
static const IconData video = IconData(0xf13b, fontFamily: "Zulip Icons");


// END GENERATED ICON DATA
}

Expand Down
4 changes: 4 additions & 0 deletions test/example_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1335,6 +1335,7 @@ InitialSnapshot initialSnapshot({
RealmDeleteOwnMessagePolicy? realmDeleteOwnMessagePolicy,
RealmWildcardMentionPolicy? realmWildcardMentionPolicy,
bool? realmMandatoryTopics,
int? realmVideoChatProvider,
String? realmName,
int? realmWaitingPeriodThreshold,
int? realmMessageContentDeleteLimitSeconds,
Expand All @@ -1344,6 +1345,7 @@ InitialSnapshot initialSnapshot({
Uri? realmIconUrl,
bool? realmPresenceDisabled,
Map<String, RealmDefaultExternalAccount>? realmDefaultExternalAccounts,
String? jitsiServerUrl,
int? maxFileUploadSizeMib,
Uri? serverEmojiDataUrl,
String? realmEmptyTopicDisplayName,
Expand Down Expand Up @@ -1398,6 +1400,7 @@ InitialSnapshot initialSnapshot({
realmDeleteOwnMessagePolicy: realmDeleteOwnMessagePolicy,
realmWildcardMentionPolicy: realmWildcardMentionPolicy ?? RealmWildcardMentionPolicy.everyone,
realmMandatoryTopics: realmMandatoryTopics ?? true,
realmVideoChatProvider: realmVideoChatProvider ?? 1,
realmName: realmName ?? 'Example Zulip organization',
realmWaitingPeriodThreshold: realmWaitingPeriodThreshold ?? 0,
realmMessageContentDeleteLimitSeconds: realmMessageContentDeleteLimitSeconds,
Expand All @@ -1407,6 +1410,7 @@ InitialSnapshot initialSnapshot({
realmIconUrl: realmIconUrl ?? _realmIcon,
realmPresenceDisabled: realmPresenceDisabled ?? false,
realmDefaultExternalAccounts: realmDefaultExternalAccounts ?? {},
jitsiServerUrl: jitsiServerUrl ?? 'https://meet.jit.si',
maxFileUploadSizeMib: maxFileUploadSizeMib ?? 25,
serverEmojiDataUrl: serverEmojiDataUrl
?? realmUrl.replace(path: '/static/emoji.json'),
Expand Down
Loading