diff --git a/lib/api/marianumcloud/talk/deleteReactMessage/deleteReactMessage.dart b/lib/api/marianumcloud/talk/deleteReactMessage/deleteReactMessage.dart new file mode 100644 index 0000000..d7e5e42 --- /dev/null +++ b/lib/api/marianumcloud/talk/deleteReactMessage/deleteReactMessage.dart @@ -0,0 +1,26 @@ +import 'package:http/http.dart' as http; +import 'package:http/http.dart'; + +import '../../../apiParams.dart'; +import '../talkApi.dart'; +import 'deleteReactMessageParams.dart'; + +class DeleteReactMessage extends TalkApi { + String chatToken; + int messageId; + DeleteReactMessage({required this.chatToken, required this.messageId, required DeleteReactMessageParams params}) : super("v1/reaction/$chatToken/$messageId", params); + + @override + assemble(String raw) { + + } + + @override + Future? request(Uri uri, ApiParams? body, Map? headers) { + if(body is DeleteReactMessageParams) { + return http.delete(uri, headers: headers, body: body.toJson()); + } + return null; + } + +} \ No newline at end of file diff --git a/lib/api/marianumcloud/talk/deleteReactMessage/deleteReactMessageParams.dart b/lib/api/marianumcloud/talk/deleteReactMessage/deleteReactMessageParams.dart new file mode 100644 index 0000000..93f13cb --- /dev/null +++ b/lib/api/marianumcloud/talk/deleteReactMessage/deleteReactMessageParams.dart @@ -0,0 +1,15 @@ +import 'package:json_annotation/json_annotation.dart'; + +import '../../../apiParams.dart'; + +part 'deleteReactMessageParams.g.dart'; + +@JsonSerializable() +class DeleteReactMessageParams extends ApiParams { + String reaction; + + DeleteReactMessageParams(this.reaction); + + factory DeleteReactMessageParams.fromJson(Map json) => _$DeleteReactMessageParamsFromJson(json); + Map toJson() => _$DeleteReactMessageParamsToJson(this); +} \ No newline at end of file diff --git a/lib/api/marianumcloud/talk/deleteReactMessage/deleteReactMessageParams.g.dart b/lib/api/marianumcloud/talk/deleteReactMessage/deleteReactMessageParams.g.dart new file mode 100644 index 0000000..f87c080 --- /dev/null +++ b/lib/api/marianumcloud/talk/deleteReactMessage/deleteReactMessageParams.g.dart @@ -0,0 +1,19 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'deleteReactMessageParams.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +DeleteReactMessageParams _$DeleteReactMessageParamsFromJson( + Map json) => + DeleteReactMessageParams( + json['reaction'] as String, + ); + +Map _$DeleteReactMessageParamsToJson( + DeleteReactMessageParams instance) => + { + 'reaction': instance.reaction, + }; diff --git a/lib/api/marianumcloud/talk/reactMessage/reactMessage.dart b/lib/api/marianumcloud/talk/reactMessage/reactMessage.dart new file mode 100644 index 0000000..ba86bbe --- /dev/null +++ b/lib/api/marianumcloud/talk/reactMessage/reactMessage.dart @@ -0,0 +1,26 @@ +import 'package:http/http.dart' as http; +import 'package:http/http.dart'; + +import '../../../apiParams.dart'; +import '../talkApi.dart'; +import 'reactMessageParams.dart'; + +class ReactMessage extends TalkApi { + String chatToken; + int messageId; + ReactMessage({required this.chatToken, required this.messageId, required ReactMessageParams params}) : super("v1/reaction/$chatToken/$messageId", params); + + @override + assemble(String raw) { + + } + + @override + Future? request(Uri uri, ApiParams? body, Map? headers) { + if(body is ReactMessageParams) { + return http.post(uri, headers: headers, body: body.toJson()); + } + return null; + } + +} \ No newline at end of file diff --git a/lib/api/marianumcloud/talk/reactMessage/reactMessageParams.dart b/lib/api/marianumcloud/talk/reactMessage/reactMessageParams.dart new file mode 100644 index 0000000..05ef0ac --- /dev/null +++ b/lib/api/marianumcloud/talk/reactMessage/reactMessageParams.dart @@ -0,0 +1,15 @@ +import 'package:json_annotation/json_annotation.dart'; + +import '../../../apiParams.dart'; + +part 'reactMessageParams.g.dart'; + +@JsonSerializable() +class ReactMessageParams extends ApiParams { + String reaction; + + ReactMessageParams(this.reaction); + + factory ReactMessageParams.fromJson(Map json) => _$ReactMessageParamsFromJson(json); + Map toJson() => _$ReactMessageParamsToJson(this); +} \ No newline at end of file diff --git a/lib/api/marianumcloud/talk/reactMessage/reactMessageParams.g.dart b/lib/api/marianumcloud/talk/reactMessage/reactMessageParams.g.dart new file mode 100644 index 0000000..dd900b7 --- /dev/null +++ b/lib/api/marianumcloud/talk/reactMessage/reactMessageParams.g.dart @@ -0,0 +1,17 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'reactMessageParams.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +ReactMessageParams _$ReactMessageParamsFromJson(Map json) => + ReactMessageParams( + json['reaction'] as String, + ); + +Map _$ReactMessageParamsToJson(ReactMessageParams instance) => + { + 'reaction': instance.reaction, + }; diff --git a/lib/api/marianumcloud/talk/talkApi.dart b/lib/api/marianumcloud/talk/talkApi.dart index 26e0bc7..ed4830b 100644 --- a/lib/api/marianumcloud/talk/talkApi.dart +++ b/lib/api/marianumcloud/talk/talkApi.dart @@ -42,9 +42,11 @@ abstract class TalkApi extends ApiRequest { try { data = await request(endpoint, body, headers); - if(data == null) throw Exception(); + if(data == null) throw Exception("No response Data"); + if(data.statusCode >= 400 || data.statusCode < 200) throw Exception("Response status code '${data.statusCode}' might indicate an error"); } catch(e) { - throw ApiError("Request could not be dispatched!"); + log(e.toString()); + throw ApiError("Request could not be dispatched: ${e.toString()}"); } //dynamic jsonData = jsonDecode(data.body); diff --git a/lib/view/pages/talk/chatBubble.dart b/lib/view/pages/talk/chatBubble.dart index a5235aa..d8eea1b 100644 --- a/lib/view/pages/talk/chatBubble.dart +++ b/lib/view/pages/talk/chatBubble.dart @@ -8,6 +8,10 @@ import 'package:provider/provider.dart'; import '../../../api/marianumcloud/talk/chat/getChatResponse.dart'; import '../../../api/marianumcloud/talk/deleteMessage/deleteMessage.dart'; +import '../../../api/marianumcloud/talk/deleteReactMessage/deleteReactMessage.dart'; +import '../../../api/marianumcloud/talk/deleteReactMessage/deleteReactMessageParams.dart'; +import '../../../api/marianumcloud/talk/reactMessage/reactMessage.dart'; +import '../../../api/marianumcloud/talk/reactMessage/reactMessageParams.dart'; import '../../../api/marianumcloud/talk/room/getRoomResponse.dart'; import '../../../model/chatList/chatProps.dart'; import '../../../theming/appTheme.dart'; @@ -21,11 +25,14 @@ class ChatBubble extends StatefulWidget { final GetChatResponseObject bubbleData; final GetRoomResponseObject chatData; + final void Function({bool renew}) refetch; + const ChatBubble({ required this.context, required this.isSender, required this.bubbleData, required this.chatData, + required this.refetch, Key? key}) : super(key: key); @override @@ -168,8 +175,30 @@ class _ChatBubbleState extends State { ), onLongPress: () { showDialog(context: context, builder: (context) { + List commonReactions = ["😆", "👍", "👎", "❤️", "💔", "😍"]; return SimpleDialog( children: [ + Wrap( + alignment: WrapAlignment.center, + children: [ + ...commonReactions.map((e) => TextButton( + style: TextButton.styleFrom( + padding: EdgeInsets.zero, + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + minimumSize: const Size(40, 40) + ), + onPressed: () { + Navigator.of(context).pop(); + ReactMessage( + chatToken: widget.chatData.token, + messageId: widget.bubbleData.id, + params: ReactMessageParams(e), + ).run().then((value) => widget.refetch(renew: true)); + }, + child: Text(e)), + ), + ], + ), Visibility( visible: !message.containsFile && widget.bubbleData.messageType == GetRoomResponseObjectMessageType.comment, child: ListTile( @@ -268,15 +297,38 @@ class _ChatBubbleState extends State { child: Wrap( alignment: widget.isSender ? WrapAlignment.end : WrapAlignment.start, crossAxisAlignment: WrapCrossAlignment.start, - //mainAxisSize: MainAxisSize.max, children: widget.bubbleData.reactions?.entries.map((e) { + bool hasSelfReacted = widget.bubbleData.reactionsSelf?.contains(e.key) ?? false; return Container( margin: const EdgeInsets.only(right: 2.5, left: 2.5), - child: Chip( + child: ActionChip( label: Text("${e.key} ${e.value}"), visualDensity: const VisualDensity(vertical: VisualDensity.minimumDensity, horizontal: VisualDensity.minimumDensity), padding: EdgeInsets.zero, - backgroundColor: widget.bubbleData.reactionsSelf?.contains(e.key) ?? false ? Theme.of(context).primaryColor : null, + backgroundColor: hasSelfReacted ? Theme.of(context).primaryColor : null, + onPressed: () { + if(hasSelfReacted) { + // Delete existing reaction + DeleteReactMessage( + chatToken: widget.chatData.token, + messageId: widget.bubbleData.id, + params: DeleteReactMessageParams( + e.key + ), + ).run().then((value) => widget.refetch(renew: true)); + + } else { + // Add reaction + ReactMessage( + chatToken: widget.chatData.token, + messageId: widget.bubbleData.id, + params: ReactMessageParams( + e.key + ) + ).run().then((value) => widget.refetch(renew: true)); + + } + }, ), ); }).toList() ?? [], diff --git a/lib/view/pages/talk/chatView.dart b/lib/view/pages/talk/chatView.dart index e522c72..71ee2b9 100644 --- a/lib/view/pages/talk/chatView.dart +++ b/lib/view/pages/talk/chatView.dart @@ -31,9 +31,13 @@ class _ChatViewState extends State { super.initState(); WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - Provider.of(context, listen: false).setQueryToken(widget.room.token); + _query(); }); } + + void _query({bool renew = false}) { + Provider.of(context, listen: false).setQueryToken(widget.room.token); + } @override Widget build(BuildContext context) { @@ -52,13 +56,14 @@ class _ChatViewState extends State { if(elementDate.weekday != lastDate.weekday) { lastDate = elementDate; messages.add(ChatBubble( - context: context, - isSender: true, - bubbleData: GetChatResponseObject.getDateDummy(element.timestamp), - chatData: widget.room + context: context, + isSender: true, + bubbleData: GetChatResponseObject.getDateDummy(element.timestamp), + chatData: widget.room, + refetch: _query, )); } - messages.add(ChatBubble(context: context, isSender: element.actorId == widget.selfId, bubbleData: element, chatData: widget.room)); + messages.add(ChatBubble(context: context, isSender: element.actorId == widget.selfId, bubbleData: element, chatData: widget.room, refetch: _query)); }); }