import 'dart:convert'; import 'dart:typed_data'; import 'package:audio_waveforms/audio_waveforms.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:mohem_flutter_app/api/api_client.dart'; import 'package:mohem_flutter_app/api/chat/chat_api_client.dart'; import 'package:mohem_flutter_app/app_state/app_state.dart'; import 'package:mohem_flutter_app/classes/colors.dart'; import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart'; import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/ui/chat/chat_full_image_preview.dart'; import 'package:mohem_flutter_app/widgets/bottom_sheet.dart'; import 'package:open_file/open_file.dart'; import 'package:provider/provider.dart'; // todo: @aamir use extension methods, and use correct widgets. class ChatBubble extends StatelessWidget { ChatBubble({Key? key, required this.dateTime, required this.cItem}) : super(key: key); final String dateTime; final SingleUserChatModel cItem; bool isCurrentUser = false; bool isSeen = false; bool isReplied = false; int? fileTypeID; String? fileTypeName; late ChatProviderModel data; String? fileTypeDescription; bool isDelivered = false; String userName = ''; late Offset screenOffset; void makeAssign() { isCurrentUser = cItem.currentUserId == AppState().chatDetails!.response!.id ? true : false; isSeen = cItem.isSeen == true ? true : false; isReplied = cItem.userChatReplyResponse != null ? true : false; fileTypeID = cItem.fileTypeId; fileTypeName = cItem.fileTypeResponse != null ? cItem.fileTypeResponse!.fileTypeName : ""; fileTypeDescription = cItem.fileTypeResponse != null ? cItem.fileTypeResponse!.fileTypeDescription : ""; isDelivered = cItem.currentUserId == AppState().chatDetails!.response!.id && cItem.isDelivered == true ? true : false; userName = AppState().chatDetails!.response!.userName == cItem.currentUserName.toString() ? "You" : cItem.currentUserName.toString(); } @override Widget build(BuildContext context) { Size windowSize = MediaQuery.of(context).size; screenOffset = Offset(windowSize.width / 2, windowSize.height / 2); makeAssign(); data = Provider.of(context, listen: false); return isCurrentUser ? currentUser(context) : receiptUser(context); } Widget currentUser(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (isReplied) ClipRRect( borderRadius: BorderRadius.circular(5.0), child: Container( width: double.infinity, decoration: BoxDecoration( border: Border( left: BorderSide(width: 6, color: isCurrentUser ? MyColors.gradiantStartColor : MyColors.white), ), color: isCurrentUser ? MyColors.black.withOpacity(0.10) : MyColors.black.withOpacity(0.30), ), child: Row( children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ (userName).toText12(color: MyColors.gradiantStartColor, isBold: false).paddingOnly(right: 5, top: 5, bottom: 0, left: 5), (cItem.userChatReplyResponse != null ? cItem.userChatReplyResponse!.contant.toString() : "") .toText10(color: isCurrentUser ? MyColors.grey71Color : MyColors.white.withOpacity(0.5), isBold: false, maxlines: 4) .paddingOnly(right: 5, top: 5, bottom: 8, left: 5), ], ).expanded, if (cItem.userChatReplyResponse != null && cItem.userChatReplyResponse!.fileTypeId == 12 || cItem.userChatReplyResponse!.fileTypeId == 3 || cItem.userChatReplyResponse!.fileTypeId == 4) ClipRRect( borderRadius: BorderRadius.circular(8.0), child: SizedBox( height: 32, width: 32, child: showImage( isReplyPreview: true, fileName: cItem.userChatReplyResponse!.contant!, fileTypeDescription: cItem.userChatReplyResponse!.fileTypeResponse!.fileTypeDescription ?? "image/jpg") .paddingOnly(left: 10, right: 10, bottom: 16, top: 16), ), ), ], ), ), ).paddingOnly(bottom: 7), if (fileTypeID == 12 || fileTypeID == 4 || fileTypeID == 3) ClipRRect( borderRadius: BorderRadius.circular(5.0), child: SizedBox( height: 140, width: 227, child: showImage(isReplyPreview: false, fileName: cItem.contant!, fileTypeDescription: cItem.fileTypeResponse!.fileTypeDescription).onPress(() { showDialog( context: context, anchorPoint: screenOffset, builder: (BuildContext context) => ChatImagePreviewScreen(imgTitle: cItem.contant!, img: cItem.image!), ); }), ), ).paddingOnly(bottom: 4) else Row( children: [ if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 // || fileTypeID == 2 ) SvgPicture.asset(data.getType(fileTypeName ?? ""), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 0, right: 10), (cItem.contant ?? "").toText12().expanded, if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 //|| fileTypeID == 2 ) const Icon(Icons.remove_red_eye, size: 16) ], ), Align( alignment: Alignment.centerRight, child: Row( mainAxisSize: MainAxisSize.min, children: [ dateTime.toText10( color: MyColors.grey41Color.withOpacity(.5), ), 7.width, Icon(isDelivered ? Icons.done_all : Icons.done_all, color: isSeen ? MyColors.textMixColor : MyColors.grey9DColor, size: 14), ], ), ), ], ).paddingOnly(top: 11, left: 13, right: 13, bottom: 5).objectContainerView(disablePadding: true).paddingOnly(left: MediaQuery.of(context).size.width * 0.3); } Widget receiptUser(BuildContext context) { return Container( padding: const EdgeInsets.only(top: 11, left: 13, right: 13, bottom: 5), decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), gradient: const LinearGradient( transform: GradientRotation(.83), begin: Alignment.topRight, end: Alignment.bottomLeft, colors: [ MyColors.gradiantEndColor, MyColors.gradiantStartColor, ], ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (isReplied) ClipRRect( borderRadius: BorderRadius.circular(5.0), child: Container( width: double.infinity, decoration: BoxDecoration( border: Border(left: BorderSide(width: 6, color: isCurrentUser ? MyColors.gradiantStartColor : MyColors.white)), color: isCurrentUser ? MyColors.black.withOpacity(0.10) : MyColors.black.withOpacity(0.30), ), child: Row( children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ (userName).toText12(color: MyColors.gradiantStartColor, isBold: false).paddingOnly(right: 5, top: 5, bottom: 0, left: 5), (cItem.userChatReplyResponse != null ? cItem.userChatReplyResponse!.contant.toString() : "") .toText10(color: isCurrentUser ? MyColors.grey71Color : MyColors.white.withOpacity(0.5), isBold: false, maxlines: 4) .paddingOnly(right: 5, top: 5, bottom: 8, left: 5), ], ).expanded, if (cItem.userChatReplyResponse != null && cItem.userChatReplyResponse!.fileTypeId == 12 || cItem.userChatReplyResponse!.fileTypeId == 3 || cItem.userChatReplyResponse!.fileTypeId == 4) ClipRRect( borderRadius: BorderRadius.circular(8.0), child: SizedBox( height: 32, width: 32, child: showImage( isReplyPreview: true, fileName: cItem.userChatReplyResponse!.contant!, fileTypeDescription: cItem.userChatReplyResponse!.fileTypeResponse!.fileTypeDescription ?? "image/jpg"), ), ).paddingOnly(left: 10, right: 10, bottom: 16, top: 16) ], ), ), ).paddingOnly(bottom: 7), if (fileTypeID == 12 || fileTypeID == 4 || fileTypeID == 3) ClipRRect( borderRadius: BorderRadius.circular(5.0), child: SizedBox( height: 140, width: 227, child: showImage(isReplyPreview: false, fileName: cItem.contant ?? "", fileTypeDescription: cItem.fileTypeResponse!.fileTypeDescription ?? "image/jpg").onPress(() { showDialog( context: context, anchorPoint: screenOffset, builder: (BuildContext context) => ChatImagePreviewScreen(imgTitle: cItem.contant ?? "", img: cItem.image!), ); }), ), ).paddingOnly(bottom: 4) else Row( children: [ if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 // || fileTypeID == 2 ) SvgPicture.asset(data.getType(fileTypeName ?? ""), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover).paddingOnly(left: 0, right: 10), (cItem.contant ?? "").toText12(color: Colors.white).expanded, if (fileTypeID == 1 || fileTypeID == 5 || fileTypeID == 7 || fileTypeID == 6 || fileTypeID == 8 //|| fileTypeID == 2 ) const Icon(Icons.remove_red_eye, color: Colors.white, size: 16) ], ), Align( alignment: Alignment.centerRight, child: dateTime.toText10( color: Colors.white.withOpacity(.71), ), ), ], ), ).paddingOnly(right: MediaQuery.of(context).size.width * 0.3); } Widget showImage({required bool isReplyPreview, required String fileName, required String fileTypeDescription}) { if (isReplyPreview) {} if (cItem.isImageLoaded! && cItem.image != null) { return Image.memory( cItem.image!, height: isReplyPreview ? 32 : 140, width: isReplyPreview ? 32 : 227, fit: BoxFit.cover, alignment: Alignment.center, ); } else { return FutureBuilder( future: ChatApiClient().downloadURL(fileName: fileName, fileTypeDescription: fileTypeDescription), builder: (BuildContext context, AsyncSnapshot snapshot) { if (snapshot.connectionState != ConnectionState.waiting) { if (snapshot.data == null) { return const SizedBox(); } else { cItem.image = snapshot.data; cItem.isImageLoaded = true; return Image.memory( snapshot.data, height: isReplyPreview ? 32 : 140, width: isReplyPreview ? 32 : 227, fit: BoxFit.cover, alignment: Alignment.center, ); } } else { return SizedBox( height: isReplyPreview ? 32 : 140, width: isReplyPreview ? 32 : 227, ).toShimmer(); } }, ); } } } class WaveBubble extends StatelessWidget { final PlayerController playerController; final VoidCallback onTap; final bool isPlaying; const WaveBubble({ Key? key, required this.playerController, required this.onTap, required this.isPlaying, }) : super(key: key); @override Widget build(BuildContext context) { return Container( margin: const EdgeInsets.all(10), decoration: BoxDecoration( borderRadius: BorderRadius.circular(30), gradient: const LinearGradient( transform: GradientRotation(.83), begin: Alignment.topRight, end: Alignment.bottomLeft, colors: [ MyColors.gradiantEndColor, MyColors.gradiantStartColor, ], ), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( onPressed: onTap, icon: Icon(isPlaying ? Icons.stop : Icons.play_arrow), color: Colors.white, splashColor: Colors.transparent, highlightColor: Colors.transparent, ), AudioFileWaveforms( size: Size(MediaQuery.of(context).size.width / 2, 10), playerController: playerController, padding: EdgeInsets.zero, margin: EdgeInsets.zero, playerWaveStyle: const PlayerWaveStyle( fixedWaveColor: Colors.white, liveWaveColor:MyColors.lightGreenColor, showTop: true, showBottom: true, waveCap: StrokeCap.round, seekLineThickness: 3, visualizerHeight: 6, backgroundColor: Colors.transparent ), ), ], ), ); } }