This repository has been archived on 2024-10-18. You can view files and clone it, but cannot push or open issues or pull requests.
ftc_patient_app/lib/view/screens/chat/widgets/message_bubble.dart

421 lines
13 KiB
Dart

import 'dart:io';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:ftc_mobile_app/utilities/extensions/custom_extensions.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:ftc_mobile_app/ftc_mobile_app.dart';
import 'package:flutter/material.dart';
import 'package:photo_view/photo_view.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../../custom_widgets/my_circle_image.dart';
import 'package:path/path.dart' as path;
enum MessageType { sent, received }
enum MessageSeenStatus { delivered, seen }
enum MessageContentType { text, file, url }
enum MessageState {
stateNone(0),
stateError(-1),
stateSending(1),
stateSuccess(2);
final int intValue;
static MessageState stateFromIntValue(int value) {
switch (value) {
case -1:
return MessageState.stateError;
case 1:
return MessageState.stateSending;
case 2:
return MessageState.stateSuccess;
default:
return MessageState.stateNone;
}
}
const MessageState(this.intValue);
}
class MessageBubble extends StatelessWidget {
final String senderName;
final String content;
final MessageState state;
final MessageContentType contentType;
final String profilePic;
final MessageType type;
final MessageSeenStatus status;
final String messageTime;
final Color? sentMessageColor;
final Color? receivedMessageColor;
final Color? sentMessageTextColor;
final Color? receivedMessageTextColor;
final bool showReportButton;
const MessageBubble({
Key? key,
required this.senderName,
required this.content,
required this.contentType,
required this.state,
required this.profilePic,
required this.type,
required this.status,
required this.messageTime,
this.sentMessageColor,
this.receivedMessageColor,
this.sentMessageTextColor,
this.receivedMessageTextColor,
this.showReportButton = true,
}) : super(key: key);
Color get _backgroundColor => (type == MessageType.sent)
? (sentMessageColor ?? Get.theme.primaryColor)
: (receivedMessageColor ?? const Color(0xffC1C1C5));
Color get messageColor => (type == MessageType.sent)
? (sentMessageTextColor ?? Colors.black)
: (receivedMessageTextColor ?? Colors.white);
// double get _paddingLeft => (type == MessageType.sent) ? 0.15.sw : 0;
final radius = 16.0;
@override
Widget build(BuildContext context) {
final loader = Visibility(
visible: (state == MessageState.stateSending),
child: Align(
alignment: Alignment.topCenter,
child: SizedBox.square(
dimension: 18,
child: CircularProgressIndicator(
color: Get.theme.primaryColor,
strokeWidth: 2,
)),
),
);
final messageBox = SizedBox(
width: 0.7.sw,
child: Padding(
padding: REdgeInsets.symmetric(vertical: 5),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
(type == MessageType.received)
? MyCircleImage(
imageSize: 20.r,
url: WebUrls.baseUrl + profilePic,
errorWidget: const DecoratedBox(
decoration: BoxDecoration(color: Color(0xffC1C1C5)),
child: Center(
child: Icon(
Icons.image_not_supported_outlined,
color: Colors.black,
size: 12,
),
),
),
).paddingOnly(right: 8.r)
: FrequentFunctions.noWidget,
Expanded(
child: (contentType == MessageContentType.text)
? _textMessage()
: (content.isImageFileName)
? _imageWidget()
: _documentFileWidget(),
),
],
),
4.verticalSpace,
Row(
children: [
(type == MessageType.received)
? SizedBox(width: 28.r)
: FrequentFunctions.noWidget,
(state == MessageState.stateSending)
? loader
: (state == MessageState.stateError)
? Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
Icons.warning_amber_rounded,
color: Colors.red,
size: 14.r,
),
4.horizontalSpace,
Text(
'Message not sent',
style: const TextStyle().copyWith(
color: Colors.red,
),
)
],
)
: FrequentFunctions.noWidget
],
)
],
),
),
);
return SizedBox(
width: double.maxFinite,
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: (type == MessageType.sent)
? MainAxisAlignment.end
: MainAxisAlignment.start,
children: [messageBox],
),
);
}
Widget _textMessage() => Container(
padding: REdgeInsets.symmetric(horizontal: 14, vertical: 12),
decoration:
BoxDecoration(color: _backgroundColor, borderRadius: 10.toRadius()),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
(type == MessageType.received)
? CustomTextWidget(
text: senderName,
fontColor: messageColor,
textAlign: TextAlign.left,
fontSize: 12.sp,
fontWeight: FontWeight.w600,
).paddingOnly(bottom: 10.r)
: FrequentFunctions.noWidget,
CustomTextWidget(
text: content,
fontColor: messageColor,
textAlign: TextAlign.left,
fontSize: 12.sp,
fontWeight: FontWeight.w400,
),
4.verticalSpace,
Align(
alignment: Alignment.centerRight,
child: _messageTimeWidget(),
)
],
),
);
Widget _imageWidget() {
return InkWell(
onTap: _openPreviewDialog,
child: Container(
width: 200.r,
height: 250.r,
clipBehavior: Clip.antiAlias,
padding: REdgeInsets.all(4),
decoration: BoxDecoration(
color: _backgroundColor,
borderRadius: radius.toRadius()),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
//Sender Name
(type == MessageType.received)
? CustomTextWidget(
text: senderName,
fontColor: messageColor,
textAlign: TextAlign.left,
fontSize: 12.sp,
fontWeight: FontWeight.w600,
).paddingOnly(bottom: 10.r)
: FrequentFunctions.noWidget,
//image
Expanded(
child: ClipRRect(
clipBehavior: Clip.antiAlias,
borderRadius: (radius - 4).toRadius(),
child: (contentType == MessageContentType.file)
? Image.file(File(content), fit: BoxFit.cover)
: CachedNetworkImage(
imageUrl: (WebUrls.baseUrl + content),
fit: BoxFit.cover,
),
),
),
8.verticalSpace,
//Time
Align(
alignment: Alignment.centerRight,
child: _messageTimeWidget(),
).addPaddingHorizontal(12),
8.verticalSpace,
],
),
),
);
}
Widget _documentFileWidget() {
return Container(
decoration: BoxDecoration(
color: _backgroundColor,
borderRadius: radius.toRadius(),
),
clipBehavior: Clip.antiAlias,
padding: REdgeInsets.all(4),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
//Sender Name
(type == MessageType.received)
? CustomTextWidget(
text: senderName,
fontColor: messageColor,
textAlign: TextAlign.left,
fontSize: 12.sp,
fontWeight: FontWeight.w600,
).paddingOnly(bottom: 10.r)
: FrequentFunctions.noWidget,
//File
InkWell(
onTap: () {
if (contentType == MessageContentType.url) {
_launchUrl(WebUrls.baseUrl + content);
} else {
_launchUrl(content);
}
},
child: Card(
elevation: 0,
surfaceTintColor: Colors.white,
child: Padding(
padding: REdgeInsets.symmetric(horizontal: 12, vertical: 12),
child: Row(
children: [
CircleAvatar(
radius: 24.r,
backgroundColor:
CustomAppColors.kSecondaryColor.withOpacity(0.1),
child: const Icon(
Icons.file_copy_outlined,
color: CustomAppColors.kSecondaryColor,
),
),
12.horizontalSpace,
Expanded(
child: CustomTextWidget(
text: path.basename(content),
fontColor: messageColor,
textAlign: TextAlign.left,
fontSize: 12.sp,
fontWeight: FontWeight.w400,
),
)
],
),
),
),
),
4.verticalSpace,
//Time
Align(
alignment: Alignment.centerRight,
child: _messageTimeWidget(),
).addPaddingHorizontal(12),
],
),
);
}
Widget _messageTimeWidget() {
return (messageTime.isNotEmpty)
? Text(
DateFormat("hh:mm aa")
.format(DateTime.parse(messageTime).toLocal()),
style: TextStyle(
color: (type == MessageType.sent) ? Colors.grey : Colors.white,
fontSize: 10.sp,
fontWeight: FontWeight.w400,
),
)
: FrequentFunctions.noWidget;
}
void _openPreviewDialog() {
final img = (contentType == MessageContentType.file)
? FileImage(File(content))
: CachedNetworkImageProvider(WebUrls.baseUrl + content);
Get.dialog(
Material(
type: MaterialType.transparency,
child: SizedBox(
width: double.maxFinite,
height: double.maxFinite,
child: Stack(
fit: StackFit.expand,
children: [
Positioned.fill(
child: PhotoViewGestureDetectorScope(
axis: Axis.vertical,
child: PhotoView(
tightMode: true,
backgroundDecoration: const BoxDecoration(
color: Colors.transparent,
),
minScale: PhotoViewComputedScale.contained,
maxScale: PhotoViewComputedScale.covered * 1.1,
initialScale: PhotoViewComputedScale.contained,
imageProvider: img as ImageProvider,
heroAttributes:
const PhotoViewHeroAttributes(tag: "someTag"),
),
),
),
Positioned(
right: 12,
top: 12,
child: InkWell(
onTap: Get.back,
child: Card(
color: Colors.white,
shape: 24.toRoundedRectRadius(),
elevation: 4,
child: RSizedBox.square(
dimension: 40,
child: Icon(
Icons.close,
color: Colors.black,
size: 24.r,
),
),
),
),
)
],
),
),
),
);
}
Future<void> _launchUrl(String url) async {
try {
await launchUrl(Uri.parse(url));
} catch (e) {
debugPrint(e.toString());
}
}
}