230 lines
8.2 KiB
Dart
230 lines
8.2 KiB
Dart
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 MessageBubble extends StatefulWidget {
|
|
const MessageBubble({
|
|
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<String> attachments;
|
|
|
|
@override
|
|
State<MessageBubble> createState() => _MessageBubbleState();
|
|
}
|
|
|
|
class _MessageBubbleState extends State<MessageBubble> {
|
|
// add late here so you can access widget instance
|
|
List<bool> _isImagesLoaded = [];
|
|
final List<Timer> _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<UserProfile>().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();
|
|
}
|
|
},
|
|
));
|
|
}
|
|
}
|
|
// _isImagesLoaded = List.filled(widget.attachments.length, false);
|
|
// _timerList = List.generate(
|
|
// widget.attachments.length,
|
|
// (index) {
|
|
// return Timer.periodic(
|
|
// const Duration(milliseconds: 200),
|
|
// (timer) async {
|
|
// String imagePath =
|
|
// '${getIt.get<UserProfile>().baseImageDir}/${widget.attachments[index]}';
|
|
// File file = File(imagePath);
|
|
// if ((await file.exists())) {
|
|
// setState(() {
|
|
// _isImagesLoaded[index] = true;
|
|
// });
|
|
// timer.cancel();
|
|
// }
|
|
// },
|
|
// );
|
|
// },
|
|
// );
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
super.dispose();
|
|
for (var element in _timerList) {
|
|
element.cancel();
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
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: widget.senderId == widget.contactId
|
|
? TextDirection.ltr
|
|
: TextDirection.rtl,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
widget.senderId == widget.contactId
|
|
? getIt
|
|
.get<ContactAccountProfile>()
|
|
.friends[widget.contactId]!
|
|
.avatar
|
|
.isEmpty
|
|
? CircleAvatar(
|
|
child: Image.asset('assets/images/user_2.png'),
|
|
)
|
|
: CircleAvatar(
|
|
backgroundImage: CachedNetworkImageProvider(
|
|
'$avatarsUrl/${getIt.get<ContactAccountProfile>().friends[widget.contactId]!.avatar}',
|
|
),
|
|
)
|
|
: CircleAvatar(
|
|
backgroundImage: CachedNetworkImageProvider(
|
|
'$avatarsUrl/${getIt.get<UserProfile>().avatar}',
|
|
),
|
|
),
|
|
const SizedBox(
|
|
width: 10,
|
|
),
|
|
Expanded(
|
|
child: Column(
|
|
crossAxisAlignment: widget.senderId == widget.contactId
|
|
? CrossAxisAlignment.start
|
|
: CrossAxisAlignment.end,
|
|
children: [
|
|
// nickname
|
|
// used in group chat only
|
|
// Text('123'),
|
|
// const SizedBox(
|
|
// height: 5,
|
|
// ),
|
|
|
|
if (widget.type == 'text/multipart')
|
|
// message box
|
|
Container(
|
|
padding: const EdgeInsets.fromLTRB(10, 10, 10, 0),
|
|
decoration: BoxDecoration(
|
|
color: widget.senderId == widget.contactId
|
|
? 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<UserProfile>().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('显示信息'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|