Skip to content

Commit e9f682e

Browse files
committed
profile: Show user status
Fixes: #197
1 parent 846261a commit e9f682e

File tree

3 files changed

+46
-7
lines changed

3 files changed

+46
-7
lines changed

lib/widgets/profile.dart

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import 'page.dart';
1616
import 'remote_settings.dart';
1717
import 'store.dart';
1818
import 'text.dart';
19+
import 'theme.dart';
1920

2021
class _TextStyles {
2122
static const primaryFieldText = TextStyle(fontSize: 20);
@@ -47,6 +48,7 @@ class ProfilePage extends StatelessWidget {
4748
if (user == null) {
4849
return const _ProfileErrorPage();
4950
}
51+
final userStatus = store.getUserStatus(userId);
5052

5153
final nameStyle = _TextStyles.primaryFieldText
5254
.merge(weightVariableTextStyle(context, wght: 700));
@@ -73,17 +75,28 @@ class ProfilePage extends StatelessWidget {
7375
),
7476
// TODO write a test where the user is muted; check this and avatar
7577
TextSpan(text: store.userDisplayName(userId, replaceIfMuted: false)),
78+
UserStatusEmoji.asWidgetSpan(
79+
userId: userId,
80+
fontSize: 20,
81+
textScaler: MediaQuery.textScalerOf(context),
82+
neverAnimate: false,
83+
),
7684
]),
7785
textAlign: TextAlign.center,
7886
style: nameStyle),
87+
if (userStatus.text != null)
88+
Text(userStatus.text!,
89+
textAlign: TextAlign.center,
90+
style: TextStyle(fontSize: 18, height: 22 / 18,
91+
color: DesignVariables.of(context).userStatusText)),
92+
7993
if (displayEmail != null)
8094
Text(displayEmail,
8195
textAlign: TextAlign.center,
8296
style: _TextStyles.primaryFieldText),
8397
Text(roleToLabel(user.role, zulipLocalizations),
8498
textAlign: TextAlign.center,
8599
style: _TextStyles.primaryFieldText),
86-
// TODO(#197) render user status
87100
// TODO(#196) render active status
88101
// TODO(#292) render user local time
89102

lib/widgets/theme.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ class DesignVariables extends ThemeExtension<DesignVariables> {
213213
subscriptionListHeaderLine: const HSLColor.fromAHSL(0.2, 240, 0.1, 0.5).toColor(),
214214
subscriptionListHeaderText: const HSLColor.fromAHSL(1.0, 240, 0.1, 0.5).toColor(),
215215
unreadCountBadgeTextForChannel: Colors.black.withValues(alpha: 0.9),
216+
userStatusText: const Color(0xff808080),
216217
);
217218

218219
static final dark = DesignVariables._(
@@ -309,6 +310,8 @@ class DesignVariables extends ThemeExtension<DesignVariables> {
309310
// TODO(design-dark) need proper dark-theme color (this is ad hoc)
310311
subscriptionListHeaderText: const HSLColor.fromAHSL(1.0, 240, 0.1, 0.75).toColor(),
311312
unreadCountBadgeTextForChannel: Colors.white.withValues(alpha: 0.9),
313+
// TODO(design-dark) unchanged in dark theme?
314+
userStatusText: const Color(0xff808080),
312315
);
313316

314317
DesignVariables._({
@@ -388,6 +391,7 @@ class DesignVariables extends ThemeExtension<DesignVariables> {
388391
required this.subscriptionListHeaderLine,
389392
required this.subscriptionListHeaderText,
390393
required this.unreadCountBadgeTextForChannel,
394+
required this.userStatusText,
391395
});
392396

393397
/// The [DesignVariables] from the context's active theme.
@@ -480,6 +484,7 @@ class DesignVariables extends ThemeExtension<DesignVariables> {
480484
final Color subscriptionListHeaderLine;
481485
final Color subscriptionListHeaderText;
482486
final Color unreadCountBadgeTextForChannel;
487+
final Color userStatusText; // In Figma, but unnamed.
483488

484489
@override
485490
DesignVariables copyWith({
@@ -559,6 +564,7 @@ class DesignVariables extends ThemeExtension<DesignVariables> {
559564
Color? subscriptionListHeaderLine,
560565
Color? subscriptionListHeaderText,
561566
Color? unreadCountBadgeTextForChannel,
567+
Color? userStatusText,
562568
}) {
563569
return DesignVariables._(
564570
background: background ?? this.background,
@@ -637,6 +643,7 @@ class DesignVariables extends ThemeExtension<DesignVariables> {
637643
subscriptionListHeaderLine: subscriptionListHeaderLine ?? this.subscriptionListHeaderLine,
638644
subscriptionListHeaderText: subscriptionListHeaderText ?? this.subscriptionListHeaderText,
639645
unreadCountBadgeTextForChannel: unreadCountBadgeTextForChannel ?? this.unreadCountBadgeTextForChannel,
646+
userStatusText: userStatusText ?? this.userStatusText,
640647
);
641648
}
642649

@@ -722,6 +729,7 @@ class DesignVariables extends ThemeExtension<DesignVariables> {
722729
subscriptionListHeaderLine: Color.lerp(subscriptionListHeaderLine, other.subscriptionListHeaderLine, t)!,
723730
subscriptionListHeaderText: Color.lerp(subscriptionListHeaderText, other.subscriptionListHeaderText, t)!,
724731
unreadCountBadgeTextForChannel: Color.lerp(unreadCountBadgeTextForChannel, other.unreadCountBadgeTextForChannel, t)!,
732+
userStatusText: Color.lerp(userStatusText, other.userStatusText, t)!,
725733
);
726734
}
727735
}

test/widgets/profile_test.dart

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ import 'package:url_launcher/url_launcher.dart';
99
import 'package:zulip/api/model/events.dart';
1010
import 'package:zulip/api/model/initial_snapshot.dart';
1111
import 'package:zulip/api/model/model.dart';
12+
import 'package:zulip/basic.dart';
1213
import 'package:zulip/model/narrow.dart';
1314
import 'package:zulip/model/store.dart';
1415
import 'package:zulip/widgets/button.dart';
1516
import 'package:zulip/widgets/content.dart';
17+
import 'package:zulip/widgets/emoji.dart';
1618
import 'package:zulip/widgets/icons.dart';
1719
import 'package:zulip/widgets/message_list.dart';
1820
import 'package:zulip/widgets/page.dart';
@@ -27,6 +29,7 @@ import '../stdlib_checks.dart';
2729
import '../test_images.dart';
2830
import '../test_navigation.dart';
2931
import 'message_list_checks.dart';
32+
import 'message_list_test.dart';
3033
import 'page_checks.dart';
3134
import 'profile_page_checks.dart';
3235
import 'test_app.dart';
@@ -38,6 +41,7 @@ Future<void> setupPage(WidgetTester tester, {
3841
required int pageUserId,
3942
List<User>? users,
4043
List<int>? mutedUserIds,
44+
List<(int userId, UserStatusChange change)>? userStatuses,
4145
List<CustomProfileField>? customProfileFields,
4246
Map<String, RealmDefaultExternalAccount>? realmDefaultExternalAccounts,
4347
bool realmPresenceDisabled = false,
@@ -60,6 +64,7 @@ Future<void> setupPage(WidgetTester tester, {
6064
if (mutedUserIds != null) {
6165
await store.setMutedUsers(mutedUserIds);
6266
}
67+
await store.changeUserStatuses(userStatuses ?? []);
6368

6469
await tester.pumpWidget(TestZulipApp(
6570
accountId: eg.selfAccount.id,
@@ -95,12 +100,25 @@ void main() {
95100
final user = eg.user(userId: 1, fullName: 'test user',
96101
deliveryEmail: '[email protected]');
97102

98-
await setupPage(tester, users: [user], pageUserId: user.userId);
99-
100-
check(because: 'find user avatar', find.byType(Avatar).evaluate()).length.equals(1);
101-
check(because: 'find user name', find.text('test user').evaluate()).isNotEmpty();
102-
check(because: 'find user delivery email', find.text('[email protected]').evaluate()).isNotEmpty();
103-
});
103+
await setupPage(tester, users: [user], pageUserId: user.userId,
104+
userStatuses: [
105+
(
106+
user.userId,
107+
UserStatusChange(
108+
text: OptionSome('Busy'),
109+
emoji: OptionSome(StatusEmoji(emojiName: 'working_on_it',
110+
emojiCode: '1f6e0', reactionType: ReactionType.unicodeEmoji)))
111+
),
112+
]);
113+
114+
check(because: 'find user avatar', find.byType(Avatar).evaluate()).length.equals(1);
115+
check(because: 'find user name', find.text('test user').evaluate()).isNotEmpty();
116+
check(because: 'find user delivery email', find.text('[email protected]').evaluate()).isNotEmpty();
117+
final statusEmojiFinder = findStatusEmoji(UnicodeEmojiWidget);
118+
checkUserStatusEmoji(statusEmojiFinder, isAnimated: true);
119+
check(because: 'find user status emoji', statusEmojiFinder).findsOne();
120+
check(because: 'find user status text', find.text('Busy')).findsOne();
121+
});
104122

105123
testWidgets('page builds; error page shows up if data is missing', (tester) async {
106124
await setupPage(tester, pageUserId: eg.selfUser.userId + 1989);

0 commit comments

Comments
 (0)