Skip to content

Commit 0df0389

Browse files
committed
compose: Implement guest user DM warning banner
1 parent 5c66e06 commit 0df0389

11 files changed

+225
-12
lines changed

assets/l10n/app_en.arb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,21 @@
415415
"others": {"type": "String", "example": "Alice, Bob"}
416416
}
417417
},
418+
"guestUserDmWarningOne": "{guestUser} is a guest in this organization.",
419+
"@guestUserDmWarningOne": {
420+
"description": "Warning shown when composing a DM to one guest user",
421+
"placeholders": {
422+
"guestUser": {"type": "String", "example": "Alice"}
423+
}
424+
},
425+
426+
"guestUserDmWarningMany": "{guestUsers} are guests in this organization.",
427+
"@guestUserDmWarningMany": {
428+
"description": "Warning shown when composing DMs to multiple guest users",
429+
"placeholders": {
430+
"guestUsers": {"type": "String", "example": "Alice, Bob, and Charlie"}
431+
}
432+
},
418433
"messageListGroupYouWithYourself": "Messages with yourself",
419434
"@messageListGroupYouWithYourself": {
420435
"description": "Message list recipient header for a DM group that only includes yourself."

lib/generated/l10n/zulip_localizations.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,18 @@ abstract class ZulipLocalizations {
645645
/// **'DMs with {others}'**
646646
String dmsWithOthersPageTitle(String others);
647647

648+
/// Warning shown when composing a DM to one guest user
649+
///
650+
/// In en, this message translates to:
651+
/// **'{guestUser} is a guest in this organization.'**
652+
String guestUserDmWarningOne(String guestUser);
653+
654+
/// Warning shown when composing DMs to multiple guest users
655+
///
656+
/// In en, this message translates to:
657+
/// **'{guestUsers} are guests in this organization.'**
658+
String guestUserDmWarningMany(String guestUsers);
659+
648660
/// Message list recipient header for a DM group that only includes yourself.
649661
///
650662
/// In en, this message translates to:

lib/generated/l10n/zulip_localizations_ar.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,16 @@ class ZulipLocalizationsAr extends ZulipLocalizations {
324324
return 'DMs with $others';
325325
}
326326

327+
@override
328+
String guestUserDmWarningOne(String guestUser) {
329+
return '$guestUser is a guest in this organization.';
330+
}
331+
332+
@override
333+
String guestUserDmWarningMany(String guestUsers) {
334+
return '$guestUsers are guests in this organization.';
335+
}
336+
327337
@override
328338
String get messageListGroupYouWithYourself => 'Messages with yourself';
329339

lib/generated/l10n/zulip_localizations_en.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,16 @@ class ZulipLocalizationsEn extends ZulipLocalizations {
324324
return 'DMs with $others';
325325
}
326326

327+
@override
328+
String guestUserDmWarningOne(String guestUser) {
329+
return '$guestUser is a guest in this organization.';
330+
}
331+
332+
@override
333+
String guestUserDmWarningMany(String guestUsers) {
334+
return '$guestUsers are guests in this organization.';
335+
}
336+
327337
@override
328338
String get messageListGroupYouWithYourself => 'Messages with yourself';
329339

lib/generated/l10n/zulip_localizations_ja.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,16 @@ class ZulipLocalizationsJa extends ZulipLocalizations {
324324
return 'DMs with $others';
325325
}
326326

327+
@override
328+
String guestUserDmWarningOne(String guestUser) {
329+
return '$guestUser is a guest in this organization.';
330+
}
331+
332+
@override
333+
String guestUserDmWarningMany(String guestUsers) {
334+
return '$guestUsers are guests in this organization.';
335+
}
336+
327337
@override
328338
String get messageListGroupYouWithYourself => 'Messages with yourself';
329339

lib/generated/l10n/zulip_localizations_nb.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,16 @@ class ZulipLocalizationsNb extends ZulipLocalizations {
324324
return 'DMs with $others';
325325
}
326326

327+
@override
328+
String guestUserDmWarningOne(String guestUser) {
329+
return '$guestUser is a guest in this organization.';
330+
}
331+
332+
@override
333+
String guestUserDmWarningMany(String guestUsers) {
334+
return '$guestUsers are guests in this organization.';
335+
}
336+
327337
@override
328338
String get messageListGroupYouWithYourself => 'Messages with yourself';
329339

lib/generated/l10n/zulip_localizations_pl.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,16 @@ class ZulipLocalizationsPl extends ZulipLocalizations {
324324
return 'DM z $others';
325325
}
326326

327+
@override
328+
String guestUserDmWarningOne(String guestUser) {
329+
return '$guestUser is a guest in this organization.';
330+
}
331+
332+
@override
333+
String guestUserDmWarningMany(String guestUsers) {
334+
return '$guestUsers are guests in this organization.';
335+
}
336+
327337
@override
328338
String get messageListGroupYouWithYourself => 'Zapiski na własne konto';
329339

lib/generated/l10n/zulip_localizations_ru.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,16 @@ class ZulipLocalizationsRu extends ZulipLocalizations {
324324
return 'DMs with $others';
325325
}
326326

327+
@override
328+
String guestUserDmWarningOne(String guestUser) {
329+
return '$guestUser is a guest in this organization.';
330+
}
331+
332+
@override
333+
String guestUserDmWarningMany(String guestUsers) {
334+
return '$guestUsers are guests in this organization.';
335+
}
336+
327337
@override
328338
String get messageListGroupYouWithYourself => 'Вы с собой';
329339

lib/generated/l10n/zulip_localizations_sk.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,16 @@ class ZulipLocalizationsSk extends ZulipLocalizations {
324324
return 'DMs with $others';
325325
}
326326

327+
@override
328+
String guestUserDmWarningOne(String guestUser) {
329+
return '$guestUser is a guest in this organization.';
330+
}
331+
332+
@override
333+
String guestUserDmWarningMany(String guestUsers) {
334+
return '$guestUsers are guests in this organization.';
335+
}
336+
327337
@override
328338
String get messageListGroupYouWithYourself => 'Messages with yourself';
329339

lib/widgets/compose_box.dart

Lines changed: 107 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1430,20 +1430,20 @@ abstract class _Banner extends StatelessWidget {
14301430
minimum: EdgeInsetsDirectional.only(start: 8, end: padEnd ? 8 : 0)
14311431
// (SafeArea.minimum doesn't take an EdgeInsetsDirectional)
14321432
.resolve(Directionality.of(context)),
1433-
child: Padding(
1434-
padding: const EdgeInsetsDirectional.fromSTEB(8, 5, 0, 5),
1435-
child: Row(
1436-
children: [
1437-
Expanded(
1433+
child: Row(
1434+
children: [
1435+
Expanded(
1436+
child: Padding(
1437+
padding: const EdgeInsetsDirectional.fromSTEB(8, 5, 0, 5),
14381438
child: Padding(
14391439
padding: const EdgeInsets.symmetric(vertical: 4),
14401440
child: Text(style: labelTextStyle,
1441-
getLabel(zulipLocalizations)))),
1442-
if (trailing != null) ...[
1443-
const SizedBox(width: 8),
1444-
trailing,
1445-
],
1446-
]))));
1441+
getLabel(zulipLocalizations))))),
1442+
if (trailing != null) ...[
1443+
const SizedBox(width: 8),
1444+
trailing,
1445+
],
1446+
])));
14471447
}
14481448
}
14491449

@@ -1475,6 +1475,42 @@ class _ErrorBanner extends _Banner {
14751475
}
14761476
}
14771477

1478+
class _WarningBanner extends _Banner {
1479+
const _WarningBanner({
1480+
required this.label,
1481+
required this.onDismiss,
1482+
});
1483+
1484+
final String label;
1485+
final VoidCallback? onDismiss;
1486+
1487+
@override
1488+
String getLabel(ZulipLocalizations zulipLocalizations) => label;
1489+
1490+
@override
1491+
Color getLabelColor(DesignVariables designVariables) =>
1492+
designVariables.btnLabelAttMediumIntWarning;
1493+
1494+
@override
1495+
Color getBackgroundColor(DesignVariables designVariables) =>
1496+
designVariables.bannerBgIntWarning;
1497+
1498+
@override
1499+
bool get padEnd => false;
1500+
1501+
@override
1502+
Widget? buildTrailing(BuildContext context) {
1503+
final designVariables = DesignVariables.of(context);
1504+
return InkWell(
1505+
splashFactory: NoSplash.splashFactory,
1506+
onTap: onDismiss,
1507+
child: Padding(
1508+
padding: const EdgeInsets.all(8.0),
1509+
child: Icon(ZulipIcons.remove,
1510+
size: 24, color: designVariables.btnLabelAttLowIntWarning)));
1511+
}
1512+
}
1513+
14781514
/// The compose box.
14791515
///
14801516
/// Takes the full screen width, covering the horizontal insets with its surface.
@@ -1512,6 +1548,8 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
15121548
@override ComposeBoxController get controller => _controller!;
15131549
ComposeBoxController? _controller;
15141550

1551+
bool _isWarningBannerDismissed = false;
1552+
15151553
@override
15161554
void onNewStore() {
15171555
switch (widget.narrow) {
@@ -1538,6 +1576,12 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
15381576
super.dispose();
15391577
}
15401578

1579+
void _dismissWarningBanner() {
1580+
setState(() {
1581+
_isWarningBannerDismissed = true;
1582+
});
1583+
}
1584+
15411585
/// An [_ErrorBanner] that replaces the compose box's text inputs.
15421586
Widget? _errorBannerComposingNotAllowed(BuildContext context) {
15431587
final store = PerAccountStoreWidget.of(context);
@@ -1567,11 +1611,62 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
15671611
return null;
15681612
}
15691613

1614+
/// A [_WarningBanner] that goes at the top of the compose box.
1615+
Widget? _warningBanner(BuildContext context) {
1616+
if (_isWarningBannerDismissed) return null;
1617+
1618+
final store = PerAccountStoreWidget.of(context);
1619+
final zulipLocalizations = ZulipLocalizations.of(context);
1620+
1621+
if (store.connection.zulipFeatureLevel! < 348 ||
1622+
!store.realmEnableGuestUserDmWarning) {
1623+
return null;
1624+
}
1625+
1626+
switch (widget.narrow) {
1627+
case DmNarrow(:final otherRecipientIds):
1628+
final guestUsers = otherRecipientIds
1629+
.map((id) => store.getUser(id))
1630+
.where((user) => user?.role == UserRole.guest)
1631+
.toList();
1632+
1633+
if (guestUsers.isEmpty) return null;
1634+
1635+
final guestNames = guestUsers
1636+
.map((user) => user != null
1637+
? store.userDisplayName(user.userId)
1638+
: zulipLocalizations.unknownUserName)
1639+
.toList();
1640+
1641+
final String formattedNames;
1642+
if (guestUsers.length == 1) {
1643+
formattedNames = guestNames[0];
1644+
} else {
1645+
final allButLast =
1646+
guestNames.sublist(0, guestNames.length - 1).join(', ');
1647+
formattedNames =
1648+
"$allButLast${guestUsers.length > 2 ? ',' : ''} and ${guestNames.last}";
1649+
}
1650+
1651+
final bannerText = guestUsers.length == 1
1652+
? zulipLocalizations.guestUserDmWarningOne(guestNames.first)
1653+
: zulipLocalizations.guestUserDmWarningMany(formattedNames);
1654+
1655+
return _WarningBanner(label: bannerText,
1656+
onDismiss: _dismissWarningBanner);
1657+
1658+
default:
1659+
return null;
1660+
}
1661+
}
1662+
15701663
@override
15711664
Widget build(BuildContext context) {
15721665
final Widget? body;
15731666

15741667
final errorBanner = _errorBannerComposingNotAllowed(context);
1668+
final warningBanner = _warningBanner(context);
1669+
15751670
if (errorBanner != null) {
15761671
return _ComposeBoxContainer(body: null, banner: errorBanner);
15771672
}
@@ -1594,6 +1689,6 @@ class _ComposeBoxState extends State<ComposeBox> with PerAccountStoreAwareStateM
15941689
// errorBanner = _ErrorBanner(label:
15951690
// ZulipLocalizations.of(context).errorSendMessageTimeout);
15961691
// }
1597-
return _ComposeBoxContainer(body: body, banner: null);
1692+
return _ComposeBoxContainer(body: body, banner: warningBanner);
15981693
}
15991694
}

0 commit comments

Comments
 (0)