|
|
|
|
@ -1,18 +1,16 @@
|
|
|
|
|
import 'dart:async';
|
|
|
|
|
import 'dart:convert';
|
|
|
|
|
|
|
|
|
|
import 'package:easy_localization/easy_localization.dart';
|
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
import 'package:flutter_svg/flutter_svg.dart';
|
|
|
|
|
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
|
|
|
|
|
import 'package:mohem_flutter_app/app_state/app_state.dart';
|
|
|
|
|
import 'package:mohem_flutter_app/classes/colors.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/generated/locale_keys.g.dart';
|
|
|
|
|
import 'package:mohem_flutter_app/main.dart';
|
|
|
|
|
import 'package:mohem_flutter_app/models/chat/call.dart';
|
|
|
|
|
import 'package:mohem_flutter_app/provider/chat_provider_model.dart';
|
|
|
|
|
import 'package:mohem_flutter_app/ui/chat/call/chat_outgoing_call_screen.dart';
|
|
|
|
|
import 'package:mohem_flutter_app/ui/chat/chat_bubble.dart';
|
|
|
|
|
import 'package:mohem_flutter_app/ui/landing/dashboard_screen.dart';
|
|
|
|
|
@ -49,9 +47,7 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
await Future.delayed(
|
|
|
|
|
const Duration(
|
|
|
|
|
milliseconds: 1000,
|
|
|
|
|
),
|
|
|
|
|
const Duration(milliseconds: 1000),
|
|
|
|
|
);
|
|
|
|
|
_rc.loadComplete();
|
|
|
|
|
}
|
|
|
|
|
@ -71,48 +67,34 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
|
|
|
|
|
|
|
|
|
|
return Scaffold(
|
|
|
|
|
backgroundColor: MyColors.backgroundColor,
|
|
|
|
|
appBar: AppBarWidget(context,
|
|
|
|
|
appBar: AppBarWidget(
|
|
|
|
|
context,
|
|
|
|
|
title: userDetails["targetUser"].userName.toString().replaceAll(".", " ").capitalizeFirstofEach,
|
|
|
|
|
showHomeButton: false,
|
|
|
|
|
image: userDetails["targetUser"].image,
|
|
|
|
|
actions: [
|
|
|
|
|
IconButton(
|
|
|
|
|
onPressed: () {
|
|
|
|
|
makeCall(
|
|
|
|
|
callType: "AUDIO",
|
|
|
|
|
con: hubConnection,
|
|
|
|
|
);
|
|
|
|
|
makeCall(callType: "AUDIO", con: hubConnection);
|
|
|
|
|
},
|
|
|
|
|
icon: SvgPicture.asset(
|
|
|
|
|
"assets/icons/chat/call.svg",
|
|
|
|
|
width: 22,
|
|
|
|
|
height: 22,
|
|
|
|
|
),
|
|
|
|
|
icon: SvgPicture.asset("assets/icons/chat/call.svg", width: 22, height: 22),
|
|
|
|
|
),
|
|
|
|
|
IconButton(
|
|
|
|
|
onPressed: () {
|
|
|
|
|
makeCall(
|
|
|
|
|
callType: "VIDEO",
|
|
|
|
|
con: hubConnection,
|
|
|
|
|
);
|
|
|
|
|
makeCall(callType: "VIDEO", con: hubConnection);
|
|
|
|
|
},
|
|
|
|
|
icon: SvgPicture.asset(
|
|
|
|
|
"assets/icons/chat/video_call.svg",
|
|
|
|
|
width: 20,
|
|
|
|
|
height: 20,
|
|
|
|
|
),
|
|
|
|
|
icon: SvgPicture.asset("assets/icons/chat/video_call.svg", width: 20, height: 20),
|
|
|
|
|
),
|
|
|
|
|
10.width,
|
|
|
|
|
]),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
body: Consumer<ChatProviderModel>(
|
|
|
|
|
builder: (BuildContext context, ChatProviderModel m, Widget? child) {
|
|
|
|
|
return (m.isLoading
|
|
|
|
|
? ChatHomeShimmer()
|
|
|
|
|
: Column(
|
|
|
|
|
children: <Widget>[
|
|
|
|
|
Expanded(
|
|
|
|
|
flex: 2,
|
|
|
|
|
child: SmartRefresher(
|
|
|
|
|
SmartRefresher(
|
|
|
|
|
enablePullDown: false,
|
|
|
|
|
enablePullUp: true,
|
|
|
|
|
onLoading: () {
|
|
|
|
|
@ -123,13 +105,14 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
|
|
|
|
|
),
|
|
|
|
|
controller: _rc,
|
|
|
|
|
reverse: true,
|
|
|
|
|
child: ListView.builder(
|
|
|
|
|
child: ListView.separated(
|
|
|
|
|
controller: m.scrollController,
|
|
|
|
|
shrinkWrap: true,
|
|
|
|
|
physics: const BouncingScrollPhysics(),
|
|
|
|
|
reverse: true,
|
|
|
|
|
itemCount: m.userChatHistory.length,
|
|
|
|
|
padding: const EdgeInsets.only(top: 20),
|
|
|
|
|
padding: const EdgeInsets.all(21),
|
|
|
|
|
separatorBuilder: (cxt, index) => 8.height,
|
|
|
|
|
itemBuilder: (BuildContext context, int i) {
|
|
|
|
|
return SwipeTo(
|
|
|
|
|
iconColor: MyColors.lightGreenColor,
|
|
|
|
|
@ -151,124 +134,51 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
).expanded,
|
|
|
|
|
if (m.isMsgReply)
|
|
|
|
|
Row(
|
|
|
|
|
SizedBox(
|
|
|
|
|
height: 82,
|
|
|
|
|
child: Row(
|
|
|
|
|
children: <Widget>[
|
|
|
|
|
Container(height: 82, color: MyColors.textMixColor, width: 6),
|
|
|
|
|
Container(
|
|
|
|
|
height: 80,
|
|
|
|
|
color: MyColors.textMixColor,
|
|
|
|
|
width: 6,
|
|
|
|
|
),
|
|
|
|
|
Expanded(
|
|
|
|
|
child: Container(
|
|
|
|
|
height: 80,
|
|
|
|
|
color: MyColors.black.withOpacity(0.10),
|
|
|
|
|
child: ListTile(
|
|
|
|
|
title: (AppState().chatDetails!.response!.userName == m.repliedMsg.first.currentUserName.toString()
|
|
|
|
|
color: MyColors.darkTextColor.withOpacity(0.10),
|
|
|
|
|
padding: const EdgeInsets.only(top: 11, left: 14, bottom: 14, right: 21),
|
|
|
|
|
child: Row(
|
|
|
|
|
children: [
|
|
|
|
|
Column(
|
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
|
children: [
|
|
|
|
|
(AppState().chatDetails!.response!.userName == m.repliedMsg.first.currentUserName.toString()
|
|
|
|
|
? "You"
|
|
|
|
|
: m.repliedMsg.first.currentUserName.toString().replaceAll(".", " "))
|
|
|
|
|
.toText14(color: MyColors.lightGreenColor),
|
|
|
|
|
subtitle: (m.repliedMsg.isNotEmpty ? m.repliedMsg.first.contant! : "").toText12(
|
|
|
|
|
color: MyColors.white,
|
|
|
|
|
maxLine: 2,
|
|
|
|
|
),
|
|
|
|
|
trailing: GestureDetector(
|
|
|
|
|
onTap: m.closeMe,
|
|
|
|
|
child: Container(
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
color: MyColors.white.withOpacity(0.5),
|
|
|
|
|
borderRadius: const BorderRadius.all(
|
|
|
|
|
Radius.circular(20),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
child: const Icon(
|
|
|
|
|
Icons.close,
|
|
|
|
|
size: 23,
|
|
|
|
|
color: MyColors.white,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
(m.repliedMsg.isNotEmpty ? m.repliedMsg.first.contant! : "").toText12(color: MyColors.grey71Color, maxLine: 2)
|
|
|
|
|
],
|
|
|
|
|
).expanded,
|
|
|
|
|
12.width,
|
|
|
|
|
const Icon(Icons.cancel, size: 23, color: MyColors.grey7BColor).onPress(m.closeMe),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
if (m.isFileSelected && m.sFileType == ".png" || m.sFileType == ".jpeg" || m.sFileType == ".jpg")
|
|
|
|
|
Card(
|
|
|
|
|
margin: EdgeInsets.zero,
|
|
|
|
|
elevation: 0,
|
|
|
|
|
child: Padding(
|
|
|
|
|
padding: const EdgeInsets.only(
|
|
|
|
|
left: 20,
|
|
|
|
|
right: 20,
|
|
|
|
|
top: 20,
|
|
|
|
|
bottom: 0,
|
|
|
|
|
),
|
|
|
|
|
child: Card(
|
|
|
|
|
margin: EdgeInsets.zero,
|
|
|
|
|
shape: RoundedRectangleBorder(
|
|
|
|
|
borderRadius: BorderRadius.circular(0),
|
|
|
|
|
),
|
|
|
|
|
elevation: 0,
|
|
|
|
|
child: Container(
|
|
|
|
|
height: 200,
|
|
|
|
|
decoration: BoxDecoration(
|
|
|
|
|
image: DecorationImage(
|
|
|
|
|
image: FileImage(
|
|
|
|
|
m.selectedFile,
|
|
|
|
|
),
|
|
|
|
|
fit: BoxFit.cover,
|
|
|
|
|
),
|
|
|
|
|
borderRadius: const BorderRadius.all(
|
|
|
|
|
Radius.circular(0),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
child: const SizedBox(
|
|
|
|
|
width: double.infinity,
|
|
|
|
|
height: 200,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
).expanded,
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
Card(
|
|
|
|
|
margin: EdgeInsets.zero,
|
|
|
|
|
child: TextField(
|
|
|
|
|
if (m.isFileSelected && m.sFileType == ".png" || m.sFileType == ".jpeg" || m.sFileType == ".jpg")
|
|
|
|
|
SizedBox(height: 200, width: double.infinity, child: Image.file(m.selectedFile, fit: BoxFit.cover)).paddingOnly(left: 21, right: 21, top: 21),
|
|
|
|
|
TextField(
|
|
|
|
|
controller: m.message,
|
|
|
|
|
decoration: InputDecoration(
|
|
|
|
|
hintText: m.isFileSelected ? m.selectedFile.path.split("/").last : LocaleKeys.typeheretoreply.tr(),
|
|
|
|
|
hintStyle: TextStyle(
|
|
|
|
|
color: m.isFileSelected ? MyColors.darkTextColor : MyColors.grey98Color,
|
|
|
|
|
fontSize: 14,
|
|
|
|
|
),
|
|
|
|
|
hintStyle: TextStyle(color: m.isFileSelected ? MyColors.darkTextColor : MyColors.grey98Color, fontSize: 14),
|
|
|
|
|
border: InputBorder.none,
|
|
|
|
|
focusedBorder: InputBorder.none,
|
|
|
|
|
enabledBorder: InputBorder.none,
|
|
|
|
|
errorBorder: InputBorder.none,
|
|
|
|
|
disabledBorder: InputBorder.none,
|
|
|
|
|
contentPadding: EdgeInsets.only(
|
|
|
|
|
left: m.sFileType.isNotEmpty ? 10 : 20,
|
|
|
|
|
right: m.sFileType.isNotEmpty ? 0 : 5,
|
|
|
|
|
top: 20,
|
|
|
|
|
bottom: 20,
|
|
|
|
|
),
|
|
|
|
|
prefixIcon: m.sFileType.isNotEmpty
|
|
|
|
|
? Row(
|
|
|
|
|
mainAxisSize: MainAxisSize.min,
|
|
|
|
|
mainAxisAlignment: MainAxisAlignment.start,
|
|
|
|
|
children: <Widget>[
|
|
|
|
|
SvgPicture.asset(
|
|
|
|
|
m.getType(m.sFileType),
|
|
|
|
|
height: 30,
|
|
|
|
|
width: 25,
|
|
|
|
|
alignment: Alignment.center,
|
|
|
|
|
fit: BoxFit.cover,
|
|
|
|
|
).paddingOnly(left: 20),
|
|
|
|
|
],
|
|
|
|
|
)
|
|
|
|
|
: null,
|
|
|
|
|
contentPadding: EdgeInsets.only(left: m.sFileType.isNotEmpty ? 10 : 20, right: m.sFileType.isNotEmpty ? 0 : 5, top: 20, bottom: 20),
|
|
|
|
|
prefixIconConstraints: BoxConstraints(),
|
|
|
|
|
prefixIcon: m.sFileType.isNotEmpty ? SvgPicture.asset(m.getType(m.sFileType), height: 30, width: 22, alignment: Alignment.center, fit: BoxFit.cover) : null,
|
|
|
|
|
suffixIcon: SizedBox(
|
|
|
|
|
width: 96,
|
|
|
|
|
child: Row(
|
|
|
|
|
@ -291,19 +201,9 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
|
|
|
|
|
Radius.circular(20),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
child: const Icon(
|
|
|
|
|
Icons.close,
|
|
|
|
|
size: 15,
|
|
|
|
|
color: MyColors.white,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
("Clear")
|
|
|
|
|
.toText11(
|
|
|
|
|
color: MyColors.redA3Color,
|
|
|
|
|
)
|
|
|
|
|
.paddingOnly(
|
|
|
|
|
left: 4,
|
|
|
|
|
child: const Icon(Icons.close, size: 15, color: MyColors.white),
|
|
|
|
|
),
|
|
|
|
|
("Clear").toText11(color: MyColors.redA3Color).paddingOnly(left: 4),
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
onPressed: () async {
|
|
|
|
|
@ -316,11 +216,7 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
|
|
|
|
|
child: IconButton(
|
|
|
|
|
padding: EdgeInsets.zero,
|
|
|
|
|
alignment: Alignment.topRight,
|
|
|
|
|
icon: const Icon(
|
|
|
|
|
Icons.attach_file_rounded,
|
|
|
|
|
size: 26,
|
|
|
|
|
color: MyColors.grey3AColor,
|
|
|
|
|
),
|
|
|
|
|
icon: const Icon(Icons.attach_file_rounded, size: 26, color: MyColors.grey3AColor),
|
|
|
|
|
onPressed: () async {
|
|
|
|
|
m.selectImageToUpload(context);
|
|
|
|
|
},
|
|
|
|
|
@ -329,25 +225,14 @@ class _ChatDetailScreenState extends State<ChatDetailScreen> {
|
|
|
|
|
IconButton(
|
|
|
|
|
alignment: Alignment.centerRight,
|
|
|
|
|
padding: EdgeInsets.zero,
|
|
|
|
|
icon: SvgPicture.asset(
|
|
|
|
|
"assets/icons/chat/chat_send_icon.svg",
|
|
|
|
|
height: 26,
|
|
|
|
|
width: 26,
|
|
|
|
|
),
|
|
|
|
|
icon: SvgPicture.asset("assets/icons/chat/chat_send_icon.svg", height: 26, width: 26),
|
|
|
|
|
onPressed: () {
|
|
|
|
|
m.sendChatMessage(
|
|
|
|
|
userDetails["targetUser"].id,
|
|
|
|
|
userDetails["targetUser"].userName,
|
|
|
|
|
context,
|
|
|
|
|
);
|
|
|
|
|
m.sendChatMessage(userDetails["targetUser"].id, userDetails["targetUser"].userName, context);
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
).paddingOnly(
|
|
|
|
|
right: 20,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
).paddingOnly(right: 20),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
],
|
|
|
|
|
|