Skip to content

Commit

Permalink
feat(neon_talk): Add room avatars
Browse files Browse the repository at this point in the history
Signed-off-by: provokateurin <kate@provokateurin.de>
  • Loading branch information
provokateurin committed Feb 26, 2024
1 parent 02f60aa commit 1e17d45
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 0 deletions.
4 changes: 4 additions & 0 deletions packages/neon/neon_talk/lib/src/pages/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'package:neon_framework/utils.dart';
import 'package:neon_framework/widgets.dart';
import 'package:neon_talk/src/blocs/talk.dart';
import 'package:neon_talk/src/widgets/message_preview.dart';
import 'package:neon_talk/src/widgets/room_avatar.dart';
import 'package:neon_talk/src/widgets/unread_indicator.dart';
import 'package:nextcloud/spreed.dart' as spreed;

Expand Down Expand Up @@ -73,6 +74,9 @@ class _TalkMainPageState extends State<TalkMainPage> {
}

return ListTile(
leading: TalkRoomAvatar(
room: room,
),
title: Text(room.displayName),
subtitle: subtitle,
trailing: trailing,
Expand Down
62 changes: 62 additions & 0 deletions packages/neon/neon_talk/lib/src/widgets/room_avatar.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import 'package:flutter/material.dart';
import 'package:neon_framework/blocs.dart';
import 'package:neon_framework/utils.dart';
import 'package:neon_framework/widgets.dart';
import 'package:nextcloud/spreed.dart' as spreed;

/// Displays the avatar of the [room].
///
/// If the room has a custom avatar it will be displayed. If that is not the case and it is a
/// [spreed.RoomType.oneToOne] the user avatar will be shown, otherwise an appropriate icon is displayed.
class TalkRoomAvatar extends StatelessWidget {
/// Creates a new Talk room avatar.
const TalkRoomAvatar({
required this.room,
super.key,
});

/// The room to display the avatar for.
final spreed.Room room;

@override
Widget build(BuildContext context) {
final account = NeonProvider.of<AccountsBloc>(context).activeAccount.value!;

if (room.isCustomAvatar ?? false) {
final brightness = Theme.of(context).brightness;

return CircleAvatar(
child: ClipOval(
child: NeonApiImage.withAccount(
account: account,
getImage: (client) => switch (brightness) {
Brightness.dark => client.spreed.avatar.getAvatarDarkRaw(token: room.token),
Brightness.light => client.spreed.avatar.getAvatarRaw(token: room.token),
},
cacheKey: 'talk-room-${room.token}-avatar-$brightness',
etag: room.avatarVersion,
expires: null,
),
),
);
}

return switch (spreed.RoomType.fromValue(room.type)) {
spreed.RoomType.oneToOne => NeonUserAvatar(
account: account,
username: room.name,
),
spreed.RoomType.group => _buildIconAvatar(Icons.group),
spreed.RoomType.public => _buildIconAvatar(Icons.link),
spreed.RoomType.changelog => _buildIconAvatar(Icons.text_snippet_outlined),
spreed.RoomType.oneToOneFormer => _buildIconAvatar(Icons.lock),
spreed.RoomType.noteToSelf => _buildIconAvatar(Icons.edit_note),
};
}

Widget _buildIconAvatar(IconData icon) => CircleAvatar(
child: Icon(
icon,
),
);
}
101 changes: 101 additions & 0 deletions packages/neon/neon_talk/test/room_avatar_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import 'package:built_collection/built_collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:neon_framework/blocs.dart';
import 'package:neon_framework/testing.dart';
import 'package:neon_framework/utils.dart';
import 'package:neon_framework/widgets.dart';
import 'package:neon_talk/src/widgets/room_avatar.dart';
import 'package:nextcloud/nextcloud.dart';
import 'package:nextcloud/spreed.dart' as spreed;
import 'package:rxdart/subjects.dart';

class MockRoom extends Mock implements spreed.Room {}

Widget wrapWidget(AccountsBloc accountsBloc, Widget child) => MaterialApp(
home: NeonProvider<AccountsBloc>(
create: (_) => accountsBloc,
child: child,
),
);

void main() {
setUpAll(() {
final storage = MockNeonStorage();
when(() => storage.requestCache).thenReturn(null);
});

testWidgets('Custom avatar', (tester) async {
final account = MockAccount();
when(() => account.id).thenReturn('');
when(() => account.client).thenReturn(NextcloudClient(Uri.parse('')));

final accountsBloc = MockAccountsBloc();
when(() => accountsBloc.activeAccount).thenAnswer((_) => BehaviorSubject.seeded(account));

final room = MockRoom();
when(() => room.isCustomAvatar).thenReturn(true);
when(() => room.token).thenReturn('abc123');
when(() => room.avatarVersion).thenReturn('');

await tester.pumpWidget(
wrapWidget(
accountsBloc,
TalkRoomAvatar(
room: room,
),
),
);
expect(find.byType(NeonApiImage), findsOne);
});

testWidgets('One to one', (tester) async {
final account = MockAccount();
when(() => account.id).thenReturn('');
when(() => account.client).thenReturn(NextcloudClient(Uri.parse('')));

final userStatusBloc = MockUserStatusBloc();
when(() => userStatusBloc.statuses).thenAnswer((_) => BehaviorSubject.seeded(BuiltMap()));

final accountsBloc = MockAccountsBloc();
when(() => accountsBloc.activeAccount).thenAnswer((_) => BehaviorSubject.seeded(account));
when(() => accountsBloc.getUserStatusBlocFor(account)).thenReturn(userStatusBloc);

final room = MockRoom();
when(() => room.isCustomAvatar).thenReturn(false);
when(() => room.type).thenReturn(spreed.RoomType.oneToOne.value);
when(() => room.name).thenReturn('');

await tester.pumpWidget(
wrapWidget(
accountsBloc,
TalkRoomAvatar(
room: room,
),
),
);
expect(find.byType(NeonUserAvatar), findsOne);
});

testWidgets('Other', (tester) async {
final account = MockAccount();

final accountsBloc = MockAccountsBloc();
when(() => accountsBloc.activeAccount).thenAnswer((_) => BehaviorSubject.seeded(account));

final room = MockRoom();
when(() => room.isCustomAvatar).thenReturn(false);
when(() => room.type).thenReturn(spreed.RoomType.group.value);

await tester.pumpWidget(
wrapWidget(
accountsBloc,
TalkRoomAvatar(
room: room,
),
),
);
expect(find.byIcon(Icons.group), findsOne);
});
}

0 comments on commit 1e17d45

Please sign in to comment.