diff --git a/lib/screen/pages/talk/chatBubble.dart b/lib/screen/pages/talk/chatBubble.dart new file mode 100644 index 0000000..07ca981 --- /dev/null +++ b/lib/screen/pages/talk/chatBubble.dart @@ -0,0 +1,133 @@ +import 'package:bubble/bubble.dart'; +import 'package:flutter/material.dart'; +import 'package:jiffy/jiffy.dart'; +import 'package:marianum_mobile/api/marianumcloud/talk/chat/getChatResponse.dart'; + +import '../../../api/marianumcloud/talk/chat/richObjectStringProcessor.dart'; +import '../../../api/marianumcloud/talk/room/getRoomResponse.dart'; + +class ChatBubble { + static const styleSystem = BubbleStyle( + color: Color(0xffd4eaf4), + borderWidth: 1, + elevation: 2, + margin: BubbleEdges.only(top: 15), + alignment: Alignment.center, + ); + + static BubbleStyle getStyleOther(bool seamless) { + return BubbleStyle( + nip: BubbleNip.leftTop, + color: seamless ? Colors.transparent : Colors.white, + borderWidth: seamless ? 0 : 1, + elevation: seamless ? 0 : 1, + margin: const BubbleEdges.only(top: 15, left: 10, right: 50), + alignment: Alignment.topLeft, + ); + } + + static BubbleStyle getStyleSelf(bool seamless) { + return BubbleStyle( + nip: BubbleNip.rightBottom, + color: seamless ? Colors.transparent : const Color(0xffd9fdd3), + borderWidth: seamless ? 0 : 1, + elevation: seamless ? 0 : 1, + margin: const BubbleEdges.only(top: 15, right: 10, left: 50), + alignment: Alignment.topRight, + ); + } + + BuildContext context; + bool isSender; + GetChatResponseObject bubbleData; + GetRoomResponseObject chatData; + + ChatBubble({ + required this.context, + required this.isSender, + required this.bubbleData, + required this.chatData, + }); + + BubbleStyle getStyle() { + BubbleStyle currentStyle; + if(bubbleData.messageType == GetRoomResponseObjectMessageType.comment) { + if(isSender) { + currentStyle = getStyleSelf(bubbleData.messageParameters?.containsKey("file") ?? false); + } else { + currentStyle = getStyleOther(bubbleData.messageParameters?.containsKey("file") ?? false); + } + } else { + currentStyle = styleSystem; + } + + return currentStyle; + } + + Bubble generateBubble() { + + bool showActorDisplayName = bubbleData.messageType == GetRoomResponseObjectMessageType.comment && chatData.type != GetRoomResponseObjectConversationType.oneToOne; + bool showBubbleTime = bubbleData.messageType != GetRoomResponseObjectMessageType.system; + var _actorTextStyle = TextStyle(color: Theme.of(context).primaryColor, fontWeight: FontWeight.bold); + + return Bubble( + margin: BubbleEdges.only(/*bottom: element == data.getChatResponse.sortByTimestamp().last ? 20 : 0*/), + + style: getStyle(), + child: Container( + constraints: BoxConstraints( + maxWidth: MediaQuery.of(context).size.width * 0.9, + minWidth: showActorDisplayName ? _textSize(bubbleData.actorDisplayName, _actorTextStyle).width : 30, + ), + child: Stack( + children: [ + Padding( + padding: EdgeInsets.only(bottom: showBubbleTime ? 18 : 0, top: showActorDisplayName ? 18 : 0), + child: FutureBuilder( + future: RichObjectStringProcessor.parseAnyToWidget(bubbleData.message, bubbleData.messageParameters), + builder: (context, snapshot) { + if(!snapshot.hasData) return const CircularProgressIndicator(); + return snapshot.data ?? const Icon(Icons.error); + }, + ) + ), + Visibility( + visible: showActorDisplayName, + child: Positioned( + top: 0, + left: 0, + child: Text( + bubbleData.actorDisplayName, + textAlign: TextAlign.start, + style: _actorTextStyle, + ), + ), + ), + Visibility( + visible: showBubbleTime, + child: Positioned( + bottom: 0, + right: 0, + child: Text( + Jiffy.unixFromSecondsSinceEpoch(bubbleData.timestamp).format("HH:mm"), + textAlign: TextAlign.end, + style: const TextStyle(color: Colors.grey, fontSize: 12), + ), + ), + ), + ], + ), + ), + ); + } + + + Size _textSize(String text, TextStyle style) { + final TextPainter textPainter = TextPainter( + text: TextSpan(text: text, style: style), + maxLines: 1, + textDirection: TextDirection.ltr) + ..layout(minWidth: 0, maxWidth: double.infinity); + return textPainter.size; + } +} \ No newline at end of file diff --git a/lib/screen/pages/talk/chatTextfield.dart b/lib/screen/pages/talk/chatTextfield.dart new file mode 100644 index 0000000..ea91587 --- /dev/null +++ b/lib/screen/pages/talk/chatTextfield.dart @@ -0,0 +1,62 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import '../../../api/marianumcloud/talk/sendMessage/sendMessage.dart'; +import '../../../api/marianumcloud/talk/sendMessage/sendMessageParams.dart'; +import '../../../data/chatList/chatProps.dart'; + +class ChatTextfield extends StatefulWidget { + String sendToToken; + ChatTextfield(this.sendToToken, {Key? key}) : super(key: key); + + @override + State createState() => _ChatTextfieldState(); +} + +class _ChatTextfieldState extends State { + final TextEditingController _textBoxController = TextEditingController(); + bool sending = false; + + @override + Widget build(BuildContext context) { + return Container( + color: Theme.of(context).dividerColor, + padding: const EdgeInsets.all(10), + child: Row( + children: [ + Expanded( + child: TextField( + controller: _textBoxController, + readOnly: sending, + maxLines: null, + decoration: const InputDecoration( + hintText: "Nachricht", + border: OutlineInputBorder(), + labelText: "", + ), + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 15), + child: sending ? const Center(child: CircularProgressIndicator()) : IconButton( + onPressed: () { + if(_textBoxController.text.isEmpty) return; + setState(() { + sending = true; + }); + SendMessage(widget.sendToToken, SendMessageParams(_textBoxController.text)).run().then((value) => { + Provider.of(context, listen: false).run(), + _textBoxController.text = "", + setState(() { + sending = false; + }), + }); + }, + icon: const Icon(Icons.send) + ), + ) + ], + ), + ); + } +} diff --git a/lib/screen/pages/talk/chatView.dart b/lib/screen/pages/talk/chatView.dart index 9e53e53..8672828 100644 --- a/lib/screen/pages/talk/chatView.dart +++ b/lib/screen/pages/talk/chatView.dart @@ -1,12 +1,10 @@ import 'package:bubble/bubble.dart'; import 'package:flutter/material.dart'; -import 'package:jiffy/jiffy.dart'; -import 'package:marianum_mobile/api/marianumcloud/talk/chat/richObjectStringProcessor.dart'; import 'package:marianum_mobile/api/marianumcloud/talk/room/getRoomResponse.dart'; -import 'package:marianum_mobile/api/marianumcloud/talk/sendMessage/sendMessage.dart'; -import 'package:marianum_mobile/api/marianumcloud/talk/sendMessage/sendMessageParams.dart'; import 'package:marianum_mobile/data/chatList/chatProps.dart'; +import 'package:marianum_mobile/screen/pages/talk/chatBubble.dart'; +import 'package:marianum_mobile/screen/pages/talk/chatTextfield.dart'; import 'package:provider/provider.dart'; class ChatView extends StatefulWidget { @@ -21,39 +19,8 @@ class ChatView extends StatefulWidget { } class _ChatViewState extends State { - static const styleSystem = BubbleStyle( - color: Color(0xffd4eaf4), - borderWidth: 1, - elevation: 2, - margin: BubbleEdges.only(top: 15), - alignment: Alignment.center, - ); - - static BubbleStyle getStyleOther(bool seamless) { - return BubbleStyle( - nip: BubbleNip.leftTop, - color: seamless ? Colors.transparent : Colors.white, - borderWidth: seamless ? 0 : 1, - elevation: seamless ? 0 : 1, - margin: const BubbleEdges.only(top: 15, left: 10, right: 50), - alignment: Alignment.topLeft, - ); - } - - static BubbleStyle getStyleSelf(bool seamless) { - return BubbleStyle( - nip: BubbleNip.rightBottom, - color: seamless ? Colors.transparent : const Color(0xffd9fdd3), - borderWidth: seamless ? 0 : 1, - elevation: seamless ? 0 : 1, - margin: const BubbleEdges.only(top: 15, right: 10, left: 50), - alignment: Alignment.topRight, - ); - } final ScrollController _listController = ScrollController(); - final TextEditingController _textBoxController = TextEditingController(); - bool sending = false; @override void initState() { @@ -71,105 +38,9 @@ class _ChatViewState extends State { List messages = List.empty(growable: true); if(!data.primaryLoading()) { - bool showActorDisplayName = true; - bool showBubbleTime = true; data.getChatResponse.sortByTimestamp().forEach((element) { - - showActorDisplayName = element.messageType == GetRoomResponseObjectMessageType.comment && widget.room.type != GetRoomResponseObjectConversationType.oneToOne; - showBubbleTime = element.messageType != GetRoomResponseObjectMessageType.system; - - BubbleStyle currentStyle; - if(element.messageType == GetRoomResponseObjectMessageType.comment) { - if(element.actorId == widget.selfId) { - currentStyle = getStyleSelf(element.messageParameters?.containsKey("file") ?? false); - } else { - currentStyle = getStyleOther(element.messageParameters?.containsKey("file") ?? false); - } - } else { - currentStyle = styleSystem; - } - - var _actorTextStyle = TextStyle(color: Theme.of(context).primaryColor, fontWeight: FontWeight.bold); - - messages.add(Bubble( - margin: BubbleEdges.only(bottom: element == data.getChatResponse.sortByTimestamp().last ? 20 : 0), - - style: currentStyle, - child: Container( - constraints: BoxConstraints( - maxWidth: MediaQuery.of(context).size.width * 0.9, - minWidth: showActorDisplayName ? _textSize(element.actorDisplayName, _actorTextStyle).width : 30, - ), - child: Stack( - children: [ - Padding( - padding: EdgeInsets.only(bottom: showBubbleTime ? 18 : 0, top: showActorDisplayName ? 18 : 0), - child: FutureBuilder( - future: RichObjectStringProcessor.parseAnyToWidget(element.message, element.messageParameters), - builder: (context, snapshot) { - if(!snapshot.hasData) return const CircularProgressIndicator(); - return snapshot.data ?? const Icon(Icons.error); - }, - ) - ), - Visibility( - visible: showActorDisplayName, - child: Positioned( - top: 0, - left: 0, - child: Text( - element.actorDisplayName, - textAlign: TextAlign.start, - style: _actorTextStyle, - ), - ), - ), - Visibility( - visible: showBubbleTime, - child: Positioned( - bottom: 0, - right: 0, - child: Text( - Jiffy.unixFromSecondsSinceEpoch(element.timestamp).format("HH:mm"), - textAlign: TextAlign.end, - style: const TextStyle(color: Colors.grey, fontSize: 12), - ), - ), - ), - ], - ), - ), - - - // Stack( - // children: [ - // Visibility( - // visible: showMetadata, - // child: Positioned( - // top: 0, - // left: 0, - // child: Expanded(child: Text(element.actorDisplayName, style: TextStyle(fontWeight: FontWeight.bold, color: Theme.of(context).primaryColor))), - // ), - // ), - // Padding( - // padding: EdgeInsets.symmetric(vertical: showMetadata ? 18 : 0), - // child: Text(RichObjectStringProcessor.parse(element.message, element.messageParameters)), - // ), - // Visibility( - // visible: showMetadata, - // child: Positioned( - // bottom: 0, - // right: 0, - // child: Text( - // "${Jiffy.unixFromSecondsSinceEpoch(element.timestamp).yMMMMd} - ${Jiffy.unixFromSecondsSinceEpoch(element.timestamp).format("HH:mm")}", - // style: TextStyle(color: Theme.of(context).disabledColor), - // ), - // ), - // ), - // ], - // ), - )); + messages.add(ChatBubble(context: context, isSender: element.actorId == widget.selfId, bubbleData: element, chatData: widget.room).generateBubble()); }); } @@ -205,45 +76,7 @@ class _ChatViewState extends State { children: messages.reversed.toList(), ), ), - Container( - color: Theme.of(context).dividerColor, - padding: const EdgeInsets.all(10), - child: Row( - children: [ - Expanded( - child: TextField( - controller: _textBoxController, - readOnly: sending, - maxLines: null, - decoration: const InputDecoration( - hintText: "Nachricht", - border: OutlineInputBorder(), - labelText: "", - ), - ), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 15), - child: sending ? const Center(child: CircularProgressIndicator()) : IconButton( - onPressed: () { - if(_textBoxController.text.isEmpty) return; - setState(() { - sending = true; - }); - SendMessage(widget.room.token, SendMessageParams(_textBoxController.text)).run().then((value) => { - Provider.of(context, listen: false).run(), - _textBoxController.text = "", - setState(() { - sending = false; - }), - }); - }, - icon: const Icon(Icons.send) - ), - ) - ], - ), - ) + ChatTextfield(widget.room.token), ], ) ), @@ -251,13 +84,4 @@ class _ChatViewState extends State { }, ); } - - Size _textSize(String text, TextStyle style) { - final TextPainter textPainter = TextPainter( - text: TextSpan(text: text, style: style), - maxLines: 1, - textDirection: TextDirection.ltr) - ..layout(minWidth: 0, maxWidth: double.infinity); - return textPainter.size; - } }