@@ -14,12 +14,14 @@ import '../generated/l10n/zulip_localizations.dart';
1414import '../model/avatar_url.dart' ;
1515import '../model/binding.dart' ;
1616import '../model/content.dart' ;
17+ import '../model/emoji.dart' ;
1718import '../model/internal_link.dart' ;
1819import '../model/katex.dart' ;
1920import '../model/presence.dart' ;
2021import 'actions.dart' ;
2122import 'code_block.dart' ;
2223import 'dialog.dart' ;
24+ import 'emoji.dart' ;
2325import 'icons.dart' ;
2426import 'inset_shadow.dart' ;
2527import 'lightbox.dart' ;
@@ -1940,6 +1942,92 @@ class _PresenceCircleState extends State<PresenceCircle> with PerAccountStoreAwa
19401942 }
19411943}
19421944
1945+ /// A user status emoji to be displayed in different parts of the app.
1946+ ///
1947+ /// Use [padding] to control the padding of status emoji from neighboring
1948+ /// widgets.
1949+ /// When there is no status emoji to be shown, the padding will be omitted too.
1950+ ///
1951+ /// Use [neverAnimate] to forcefully disable the animation for animated emojis.
1952+ /// Defaults to true.
1953+ class UserStatusEmoji extends StatelessWidget {
1954+ const UserStatusEmoji ({
1955+ super .key,
1956+ required this .userId,
1957+ required this .size,
1958+ this .padding = EdgeInsets .zero,
1959+ this .neverAnimate = true ,
1960+ });
1961+
1962+ final int userId;
1963+ final double size;
1964+ final EdgeInsetsGeometry padding;
1965+ final bool neverAnimate;
1966+
1967+ static const double _spanPadding = 4 ;
1968+
1969+ /// Creates a [WidgetSpan] with a [UserStatusEmoji] , for use in rich text;
1970+ /// before or after a text span.
1971+ ///
1972+ /// Use [position] to tell the emoji span where it is located relative to
1973+ /// another span, so that it can adjust the necessary padding from it.
1974+ static InlineSpan asWidgetSpan ({
1975+ required int userId,
1976+ required double fontSize,
1977+ required TextScaler textScaler,
1978+ StatusEmojiPosition position = StatusEmojiPosition .after,
1979+ bool neverAnimate = true ,
1980+ }) {
1981+ final (double paddingStart, double paddingEnd) = switch (position) {
1982+ StatusEmojiPosition .before => (0 , _spanPadding),
1983+ StatusEmojiPosition .after => (_spanPadding, 0 ),
1984+ };
1985+ final size = textScaler.scale (fontSize);
1986+ return WidgetSpan (
1987+ alignment: PlaceholderAlignment .middle,
1988+ child: UserStatusEmoji (userId: userId, size: size,
1989+ padding: EdgeInsetsDirectional .only (start: paddingStart, end: paddingEnd),
1990+ neverAnimate: neverAnimate));
1991+ }
1992+
1993+ @override
1994+ Widget build (BuildContext context) {
1995+ final store = PerAccountStoreWidget .of (context);
1996+ final emoji = store.getUserStatus (userId).emoji;
1997+
1998+ final placeholder = SizedBox .shrink ();
1999+ if (emoji == null ) return placeholder;
2000+
2001+ final emojiDisplay = store.emojiDisplayFor (
2002+ emojiType: emoji.reactionType,
2003+ emojiCode: emoji.emojiCode,
2004+ emojiName: emoji.emojiName)
2005+ // Web doesn't seem to respect the emojiset user settings for user status.
2006+ // .resolve(store.userSettings)
2007+ ;
2008+ return switch (emojiDisplay) {
2009+ UnicodeEmojiDisplay () => Padding (
2010+ padding: padding,
2011+ child: UnicodeEmojiWidget (size: size, emojiDisplay: emojiDisplay)),
2012+ ImageEmojiDisplay () => Padding (
2013+ padding: padding,
2014+ child: ImageEmojiWidget (
2015+ size: size,
2016+ emojiDisplay: emojiDisplay,
2017+ neverAnimate: neverAnimate,
2018+ // If image emoji fails to load, show nothing.
2019+ errorBuilder: (_, _, _) => placeholder)),
2020+ // The user-status feature doesn't support a :text_emoji:-style display.
2021+ // Also, if an image emoji's URL string doesn't parse, it'll fall back to
2022+ // a :text_emoji:-style display. We show nothing for this case.
2023+ TextEmojiDisplay () => placeholder,
2024+ };
2025+ }
2026+ }
2027+
2028+ /// The position of the status emoji span relative to another text span.
2029+ enum StatusEmojiPosition { before, after }
2030+
19432031//
19442032// Small helpers.
19452033//
0 commit comments