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:provider/provider.dart'; class ChatView extends StatefulWidget { final GetRoomResponseObject room; final String selfId; final CircleAvatar avatar; const ChatView({Key? key, required this.room, required this.selfId, required this.avatar}) : super(key: key); @override State createState() => _ChatViewState(); } class _ChatViewState extends State { static const styleSystem = BubbleStyle( color: Color(0xffd4eaf4), borderWidth: 1, elevation: 2, margin: BubbleEdges.only(top: 15), alignment: Alignment.center, ); static const styleOther = BubbleStyle( nip: BubbleNip.leftTop, color: Colors.white, borderWidth: 1, elevation: 1, margin: BubbleEdges.only(top: 15, left: 10, right: 50), alignment: Alignment.topLeft, ); static const styleSelf = BubbleStyle( nip: BubbleNip.rightBottom, color: Color(0xffd9fdd3), borderWidth: 1, elevation: 1, margin: 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() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((timeStamp) { Provider.of(context, listen: false).setQueryToken(widget.room.token); }); } @override Widget build(BuildContext context) { return Consumer( builder: (context, data, child) { 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 = styleSelf; } else { currentStyle = styleOther; } } 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: _textSize(element.actorDisplayName, _actorTextStyle).width, ), 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), // ), // ), // ), // ], // ), )); }); } return Scaffold( backgroundColor: const Color(0xffefeae2), appBar: AppBar( title: Row( children: [ widget.avatar, const SizedBox(width: 10), Expanded( child: Text(widget.room.displayName, overflow: TextOverflow.ellipsis, maxLines: 1), ) ], ), ), body: Container( decoration: const BoxDecoration( image: DecorationImage( image: AssetImage("assets/background/chat.png"), scale: 1.5, opacity: 0.5, repeat: ImageRepeat.repeat, colorFilter: ColorFilter.linearToSrgbGamma() ) ), child: data.primaryLoading() ? const Center(child: CircularProgressIndicator()) : Column( children: [ Expanded( child: ListView( reverse: true, controller: _listController, 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) ), ) ], ), ) ], ) ), ); }, ); } 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; } }