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; } }