Skip to content

Commit

Permalink
Merge pull request #2086 from nextcloud/feat/neon_talk/load-full-reac…
Browse files Browse the repository at this point in the history
…tions
  • Loading branch information
provokateurin authored May 27, 2024
2 parents c63491d + 0676a6e commit ebf3a10
Show file tree
Hide file tree
Showing 10 changed files with 486 additions and 171 deletions.
40 changes: 39 additions & 1 deletion packages/neon/neon_talk/lib/src/blocs/room.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@ abstract class TalkRoomBloc implements InteractiveBloc {
/// Adds an emoji [reaction] to the [message].
void addReaction(spreed.$ChatMessageInterface message, String reaction);

/// Removes an emoji [reaction] to the [message].
/// Removes an emoji [reaction] from the [message].
void removeReaction(spreed.$ChatMessageInterface message, String reaction);

/// Loads the emoji reactions for the [message].
void loadReactions(spreed.$ChatMessageInterface message);

/// The current room data.
BehaviorSubject<Result<spreed.Room>> get room;

Expand All @@ -41,6 +44,9 @@ abstract class TalkRoomBloc implements InteractiveBloc {
/// The last message ID that was read by everyone with read-privacy set to public.
/// {@endtemplate}
BehaviorSubject<int> get lastCommonRead;

/// Map of emoji reactions for the [messages].
BehaviorSubject<BuiltMap<int, BuiltMap<String, BuiltList<spreed.Reaction>>>> get reactions;
}

class _TalkRoomBloc extends InteractiveBloc implements TalkRoomBloc {
Expand Down Expand Up @@ -150,6 +156,9 @@ class _TalkRoomBloc extends InteractiveBloc implements TalkRoomBloc {
@override
final lastCommonRead = BehaviorSubject();

@override
final reactions = BehaviorSubject.seeded(BuiltMap());

@override
void dispose() {
pollLoop = false;
Expand All @@ -158,6 +167,7 @@ class _TalkRoomBloc extends InteractiveBloc implements TalkRoomBloc {
unawaited(room.close());
unawaited(messages.close());
unawaited(lastCommonRead.close());
unawaited(reactions.close());
super.dispose();
}

Expand Down Expand Up @@ -252,6 +262,28 @@ class _TalkRoomBloc extends InteractiveBloc implements TalkRoomBloc {
);
}

@override
Future<void> loadReactions(spreed.$ChatMessageInterface message) async {
if (reactions.value.containsKey(message.id)) {
return;
}

await wrapAction(
() async {
final response = await account.client.spreed.reaction.getReactions(
token: token,
messageId: message.id,
);

updateReactions(
message.id,
response.body.ocs.data,
);
},
refresh: () async {},
);
}

void updateLastCommonRead(String? header) {
if (header != null) {
lastCommonRead.add(int.parse(header));
Expand Down Expand Up @@ -284,6 +316,12 @@ class _TalkRoomBloc extends InteractiveBloc implements TalkRoomBloc {
}

void updateReactions(int messageId, BuiltMap<String, BuiltList<spreed.Reaction>> reactions) {
this.reactions.add(
this.reactions.value.rebuild((b) {
b[messageId] = reactions;
}),
);

updateMessage(
messageId,
(b) => b
Expand Down
143 changes: 78 additions & 65 deletions packages/neon/neon_talk/lib/src/widgets/reactions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,82 +18,95 @@ class TalkReactions extends StatelessWidget {

@override
Widget build(BuildContext context) {
final bloc = NeonProvider.of<TalkRoomBloc>(context);

const shape = RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(50)),
);

final children = <Widget>[];
for (final reaction in chatMessage.reactions.entries) {
final isSelf = chatMessage.reactionsSelf?.contains(reaction.key) ?? false;

children.add(
ActionChip(
backgroundColor: isSelf ? Theme.of(context).colorScheme.primary : null,
shape: shape,
avatar: Text(reaction.key),
label: Text(
reaction.value.toString(),
style: const TextStyle(
fontSize: 12,
fontFamily: 'monospace',
),
),
padding: EdgeInsets.zero,
labelPadding: const EdgeInsets.only(
top: -2.5,
bottom: -2.5,
right: 10,
),
onPressed: () {
final bloc = NeonProvider.of<TalkRoomBloc>(context);
return MouseRegion(
onEnter: (_) {
bloc.loadReactions(chatMessage);
},
child: StreamBuilder(
stream: bloc.reactions,
builder: (context, reactionsSnapshot) {
final reactions = reactionsSnapshot.data?[chatMessage.id];

if (isSelf) {
bloc.removeReaction(chatMessage, reaction.key);
} else {
bloc.addReaction(chatMessage, reaction.key);
}
},
),
);
}
final children = <Widget>[];
for (final reaction in chatMessage.reactions.entries) {
final isSelf = chatMessage.reactionsSelf?.contains(reaction.key) ?? false;

children.add(
ActionChip(
shape: shape,
avatar: Icon(
Icons.add_reaction_outlined,
color: Theme.of(context).colorScheme.onSurfaceVariant,
size: 16,
),
label: const SizedBox(),
padding: EdgeInsets.zero,
labelPadding: const EdgeInsets.symmetric(vertical: -2.5),
onPressed: () async {
final reaction = await showDialog<String>(
context: context,
builder: (context) => const NeonEmojiPickerDialog(),
);
if (reaction == null) {
return;
children.add(
ActionChip(
backgroundColor: isSelf ? Theme.of(context).colorScheme.primary : null,
shape: shape,
avatar: Text(reaction.key),
label: Text(
reaction.value.toString(),
style: const TextStyle(
fontSize: 12,
fontFamily: 'monospace',
),
),
tooltip: reactions?[reaction.key]?.map((r) => r.actorDisplayName).join(', '),
padding: EdgeInsets.zero,
labelPadding: const EdgeInsets.only(
top: -2.5,
bottom: -2.5,
right: 10,
),
onPressed: () {
if (isSelf) {
bloc.removeReaction(chatMessage, reaction.key);
} else {
bloc.addReaction(chatMessage, reaction.key);
}
},
),
);
}

if (!context.mounted) {
return;
}
children.add(
ActionChip(
shape: shape,
avatar: Icon(
Icons.add_reaction_outlined,
color: Theme.of(context).colorScheme.onSurfaceVariant,
size: 16,
),
label: const SizedBox(),
padding: EdgeInsets.zero,
labelPadding: const EdgeInsets.symmetric(vertical: -2.5),
onPressed: () async {
final reaction = await showDialog<String>(
context: context,
builder: (context) => const NeonEmojiPickerDialog(),
);
if (reaction == null) {
return;
}

NeonProvider.of<TalkRoomBloc>(context).addReaction(chatMessage, reaction);
},
),
);
if (!context.mounted) {
return;
}

return Row(
children: children
.intersperse(
const SizedBox(
width: 5,
bloc.addReaction(chatMessage, reaction);
},
),
)
.toList(),
);

return Row(
children: children
.intersperse(
const SizedBox(
width: 5,
),
)
.toList(),
);
},
),
);
}
}
Binary file modified packages/neon/neon_talk/test/goldens/reactions.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit ebf3a10

Please sign in to comment.