import 'dart:async'; import 'dart:io'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:together_mobile/common/constants.dart'; import 'package:together_mobile/models/contact_model.dart'; import 'package:together_mobile/models/init_get_it.dart'; import 'package:together_mobile/models/user_model.dart'; import 'package:together_mobile/request/server.dart'; class FriendMessageBubble extends StatefulWidget { const FriendMessageBubble({ super.key, required this.contactId, required this.senderId, required this.type, required this.dateTime, required this.isShowTime, required this.text, required this.attachments, }); final String contactId, senderId, type, dateTime, text; final bool isShowTime; final List attachments; @override State createState() => _FriendMessageBubbleState(); } class _FriendMessageBubbleState extends State { // add late here so you can access widget instance List _isImagesLoaded = []; final List _timerList = []; @override void initState() { super.initState(); _isImagesLoaded = List.filled(widget.attachments.length, false); for (var i = 0; i < widget.attachments.length; i++) { String imagePath = '${getIt.get().baseImageDir}/${widget.attachments[i]}'; File file = File(imagePath); if (file.existsSync()) { _isImagesLoaded[i] = true; } else { _isImagesLoaded[i] = false; _timerList.add(Timer.periodic( const Duration(milliseconds: 200), (timer) { if ((file.existsSync())) { setState(() { _isImagesLoaded[i] = true; }); timer.cancel(); } }, )); } } } @override void dispose() { super.dispose(); for (var element in _timerList) { element.cancel(); } } @override Widget build(BuildContext context) { bool isFriend = widget.senderId == widget.contactId; return Container( padding: const EdgeInsets.symmetric( vertical: kDefaultPadding / 2, horizontal: kDefaultPadding, ), child: Column( children: [ // message date time if (widget.isShowTime) SizedBox( height: 35.0, child: Text( widget.dateTime, style: const TextStyle( color: kUnActivatedColor, ), ), ), Row( textDirection: isFriend ? TextDirection.ltr : TextDirection.rtl, crossAxisAlignment: CrossAxisAlignment.start, children: [ isFriend ? getIt .get() .friends[widget.contactId]! .avatar .isEmpty ? CircleAvatar( child: Image.asset('assets/images/user_2.png'), ) : CircleAvatar( backgroundImage: CachedNetworkImageProvider( '$userAvatarsUrl/${getIt.get().friends[widget.contactId]!.avatar}', ), ) : CircleAvatar( backgroundImage: CachedNetworkImageProvider( '$userAvatarsUrl/${getIt.get().avatar}', ), ), const SizedBox( width: 10, ), Expanded( child: Column( crossAxisAlignment: isFriend ? CrossAxisAlignment.start : CrossAxisAlignment.end, children: [ if (widget.type == 'text/multipart') // message box Container( padding: const EdgeInsets.fromLTRB(10, 10, 10, 0), decoration: BoxDecoration( color: isFriend ? const Color.fromARGB(255, 241, 241, 241) : kPrimaryColor, borderRadius: BorderRadius.circular(10.0), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // text message content if (widget.text.isNotEmpty) Text( widget.text, textWidthBasis: TextWidthBasis.longestLine, ), const SizedBox( height: 10, ), // image content if have if (widget.attachments.isNotEmpty) ...List.generate( widget.attachments.length, (int index) { return Container( margin: const EdgeInsets.only( bottom: 15, ), constraints: const BoxConstraints( maxHeight: 120, ), decoration: BoxDecoration( borderRadius: BorderRadius.circular(10.0), ), child: _isImagesLoaded[index] ? Image.file(File( '${getIt.get().baseImageDir}/${widget.attachments[index]}', )) : Container( width: 20, height: 40, padding: const EdgeInsets.symmetric( vertical: 10), child: const CircularProgressIndicator( color: kSecondaryColor, strokeWidth: 3.0, ), ), ); }, ), ], ), ), ], ), ), ], ), TextButton( onPressed: () {}, style: TextButton.styleFrom( padding: EdgeInsets.zero, tapTargetSize: MaterialTapTargetSize.shrinkWrap, ), child: const Text('显示信息'), ), ], ), ); } }