Added option to add reactions to talk messages

This commit is contained in:
Elias Müller 2023-07-09 19:38:09 +02:00
parent 0b2fab5b6d
commit 2ddaa17a81
9 changed files with 188 additions and 11 deletions

@ -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<Response>? request(Uri uri, ApiParams? body, Map<String, String>? headers) {
if(body is DeleteReactMessageParams) {
return http.delete(uri, headers: headers, body: body.toJson());
}
return null;
}
}

@ -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<String, dynamic> json) => _$DeleteReactMessageParamsFromJson(json);
Map<String, dynamic> toJson() => _$DeleteReactMessageParamsToJson(this);
}

@ -0,0 +1,19 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'deleteReactMessageParams.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
DeleteReactMessageParams _$DeleteReactMessageParamsFromJson(
Map<String, dynamic> json) =>
DeleteReactMessageParams(
json['reaction'] as String,
);
Map<String, dynamic> _$DeleteReactMessageParamsToJson(
DeleteReactMessageParams instance) =>
<String, dynamic>{
'reaction': instance.reaction,
};

@ -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<Response>? request(Uri uri, ApiParams? body, Map<String, String>? headers) {
if(body is ReactMessageParams) {
return http.post(uri, headers: headers, body: body.toJson());
}
return null;
}
}

@ -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<String, dynamic> json) => _$ReactMessageParamsFromJson(json);
Map<String, dynamic> toJson() => _$ReactMessageParamsToJson(this);
}

@ -0,0 +1,17 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'reactMessageParams.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
ReactMessageParams _$ReactMessageParamsFromJson(Map<String, dynamic> json) =>
ReactMessageParams(
json['reaction'] as String,
);
Map<String, dynamic> _$ReactMessageParamsToJson(ReactMessageParams instance) =>
<String, dynamic>{
'reaction': instance.reaction,
};

@ -42,9 +42,11 @@ abstract class TalkApi<T> 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);

@ -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<ChatBubble> {
),
onLongPress: () {
showDialog(context: context, builder: (context) {
List<String> 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<ChatBubble> {
child: Wrap(
alignment: widget.isSender ? WrapAlignment.end : WrapAlignment.start,
crossAxisAlignment: WrapCrossAlignment.start,
//mainAxisSize: MainAxisSize.max,
children: widget.bubbleData.reactions?.entries.map<Widget>((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() ?? [],

@ -31,9 +31,13 @@ class _ChatViewState extends State<ChatView> {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
Provider.of<ChatProps>(context, listen: false).setQueryToken(widget.room.token);
_query();
});
}
void _query({bool renew = false}) {
Provider.of<ChatProps>(context, listen: false).setQueryToken(widget.room.token);
}
@override
Widget build(BuildContext context) {
@ -52,13 +56,14 @@ class _ChatViewState extends State<ChatView> {
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));
});
}