marco.pms.mobile/lib/view/apps/chat_screen.dart
2025-04-02 19:11:36 +05:30

343 lines
13 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_lucide/flutter_lucide.dart';
import 'package:get/get.dart';
import 'package:maxdash/controller/apps/chat_controller.dart';
import 'package:maxdash/helpers/theme/app_theme.dart';
import 'package:maxdash/helpers/utils/mixins/ui_mixin.dart';
import 'package:maxdash/helpers/utils/my_shadow.dart';
import 'package:maxdash/helpers/utils/utils.dart';
import 'package:maxdash/helpers/widgets/my_breadcrumb.dart';
import 'package:maxdash/helpers/widgets/my_breadcrumb_item.dart';
import 'package:maxdash/helpers/widgets/my_button.dart';
import 'package:maxdash/helpers/widgets/my_card.dart';
import 'package:maxdash/helpers/widgets/my_container.dart';
import 'package:maxdash/helpers/widgets/my_flex.dart';
import 'package:maxdash/helpers/widgets/my_flex_item.dart';
import 'package:maxdash/helpers/widgets/my_spacing.dart';
import 'package:maxdash/helpers/widgets/my_text.dart';
import 'package:maxdash/helpers/widgets/my_text_style.dart';
import 'package:maxdash/images.dart';
import 'package:maxdash/model/chat_model.dart';
import 'package:maxdash/view/layouts/layout.dart';
class ChatScreen extends StatefulWidget {
const ChatScreen({super.key});
@override
State<ChatScreen> createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> with UIMixin {
ChatController controller = Get.put(ChatController());
@override
Widget build(BuildContext context) {
return Layout(
child: GetBuilder(
init: controller,
tag: 'chat_controller',
builder: (controller) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: MySpacing.x(flexSpacing),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
MyText.titleMedium(
"Chat",
fontSize: 18,
fontWeight: 600,
),
MyBreadcrumb(
children: [
MyBreadcrumbItem(name: 'App'),
MyBreadcrumbItem(name: 'Chat'),
],
),
],
),
),
MySpacing.height(flexSpacing),
Padding(
padding: MySpacing.x(flexSpacing / 2),
child: MyFlex(
children: [
MyFlexItem(sizes: 'lg-4', child: SizedBox(height: 800, child: chatIndex())),
MyFlexItem(sizes: 'lg-8', child: SizedBox(height: 800, child: messages())),
],
),
),
],
);
},
),
);
}
Widget chatIndex() {
Widget searchField() {
return TextFormField(
onChanged: controller.onSearchChat,
style: MyTextStyle.bodyMedium(),
decoration: InputDecoration(
border: OutlineInputBorder(),
errorBorder: OutlineInputBorder(),
enabledBorder: OutlineInputBorder(),
focusedErrorBorder: OutlineInputBorder(),
focusedBorder: OutlineInputBorder(),
disabledBorder: OutlineInputBorder(),
prefixIcon: Icon(LucideIcons.search),
hintText: "Search",
hintStyle: MyTextStyle.bodyMedium(),
contentPadding: MySpacing.all(16),
isCollapsed: true,
isDense: true,
),
);
}
Widget users() {
return Expanded(
child: ListView.separated(
itemCount: controller.searchChat.length,
shrinkWrap: true,
itemBuilder: (context, index) {
ChatModel chat = controller.searchChat[index];
return MyButton(
onPressed: () => controller.onChangeChat(chat),
padding: MySpacing.all(24),
backgroundColor: theme.colorScheme.surface.withAlpha(5),
splashColor: theme.colorScheme.onSurface.withAlpha(10),
child: Row(
children: [
MyContainer.rounded(
height: 44,
width: 44,
paddingAll: 0,
child: Image.asset(chat.avatar),
),
MySpacing.width(24),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MyText.bodyMedium(chat.firstName, fontWeight: 600),
MySpacing.height(4),
MyText.labelSmall(chat.messages.lastOrNull!.message, fontWeight: 600, muted: true),
],
),
),
],
),
);
},
separatorBuilder: (context, index) {
return Divider(height: 0);
},
),
);
}
return MyCard.bordered(
borderRadiusAll: 4,
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
paddingAll: 0,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: MySpacing.all(24),
child: searchField(),
),
Padding(
padding: MySpacing.nTop(24),
child: MyText.bodyMedium("Conversations", fontWeight: 600),
),
Divider(height: 0),
users(),
],
));
}
Widget messages() {
Widget sendMessage() {
return Row(
children: [
Expanded(
child: TextFormField(
maxLines: 3,
minLines: 1,
controller: controller.messageController,
clipBehavior: Clip.antiAliasWithSaveLayer,
style: MyTextStyle.bodyMedium(fontWeight: 600),
decoration: InputDecoration(
isDense: true,
contentPadding: MySpacing.xy(12, 16),
hintText: "Send message...",
hintStyle: MyTextStyle.bodyMedium(fontWeight: 600),
border: OutlineInputBorder(),
errorBorder: OutlineInputBorder(),
enabledBorder: OutlineInputBorder(),
focusedErrorBorder: OutlineInputBorder(),
focusedBorder: OutlineInputBorder(),
disabledBorder: OutlineInputBorder(),
),
),
),
MySpacing.width(24),
MyContainer(
onTap: () => controller.sendMessage(),
paddingAll: 0,
height: 43,
width: 43,
borderRadiusAll: 8,
clipBehavior: Clip.antiAliasWithSaveLayer,
color: contentTheme.primary,
child: Icon(LucideIcons.send, size: 20, color: contentTheme.onPrimary),
)
],
);
}
return MyCard.bordered(
borderRadiusAll: 4,
border: Border.all(color: Colors.grey.withValues(alpha:.2)),
shadow: MyShadow(elevation: 1, position: MyShadowPosition.bottom),
paddingAll: 0,
child: Column(
children: [
Padding(
padding: MySpacing.all(24),
child: Row(
children: [
if (controller.selectChat != null)
MyContainer.rounded(
height: 44,
width: 44,
paddingAll: 0,
clipBehavior: Clip.antiAliasWithSaveLayer,
child: Image.asset(controller.selectChat!.avatar, fit: BoxFit.cover),
),
MySpacing.width(12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (controller.selectChat != null) MyText.bodyMedium(controller.selectChat!.firstName, fontWeight: 600),
MyText.bodySmall("Active Now", fontWeight: 600, muted: true)
],
),
),
IconButton(onPressed: () {}, icon: Icon(LucideIcons.phone_call, size: 20)),
IconButton(onPressed: () {}, icon: Icon(LucideIcons.video, size: 20)),
PopupMenuButton(
position: PopupMenuPosition.under,
itemBuilder: (BuildContext context) => [
PopupMenuItem(padding: MySpacing.xy(16, 8), height: 10, child: MyText.bodySmall("View Contact")),
PopupMenuItem(padding: MySpacing.xy(16, 8), height: 10, child: MyText.bodySmall("Create Shortcut")),
PopupMenuItem(padding: MySpacing.xy(16, 8), height: 10, child: MyText.bodySmall("Clear Chat")),
PopupMenuItem(padding: MySpacing.xy(16, 8), height: 10, child: MyText.bodySmall("Block")),
],
child: Icon(LucideIcons.ellipsis_vertical, size: 18),
),
],
),
),
Divider(height: 0),
Expanded(
child: ListView.separated(
controller: controller.scrollController,
itemCount: (controller.selectChat?.messages ?? []).length,
padding: MySpacing.all(24),
itemBuilder: (context, index) {
final message = (controller.selectChat?.messages ?? [])[index];
final isSent = message.fromMe == true;
final theme = isSent ? contentTheme.primary : contentTheme.secondary;
return Row(
mainAxisAlignment: isSent ? MainAxisAlignment.end : MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (!isSent)
Column(
children: [
MyContainer.rounded(
height: 32,
width: 32,
paddingAll: 0,
child: Image.asset(controller.selectChat!.avatar, fit: BoxFit.cover),
),
MySpacing.height(8),
MyText.bodySmall(
'${Utils.getTimeStringFromDateTime(message.sendAt, showSecond: false)}',
fontSize: 8,
muted: true,
fontWeight: 600,
),
],
),
MySpacing.width(12),
Expanded(
child: Wrap(
alignment: isSent ? WrapAlignment.end : WrapAlignment.start,
children: [
MyContainer(
padding: EdgeInsets.all(8),
margin: EdgeInsets.only(
left: isSent ? MediaQuery.of(context).size.width * 0.20 : 0,
right: isSent ? 0 : MediaQuery.of(context).size.width * 0.20,
),
color: theme.withAlpha(30),
child: MyText.bodyMedium(
message.message,
fontWeight: 600,
color: isSent ? contentTheme.primary : contentTheme.secondary,
overflow: TextOverflow.clip,
)),
],
),
),
MySpacing.width(12),
if (controller.selectChat != null && isSent)
Column(
children: [
MyContainer.rounded(
height: 32,
width: 32,
paddingAll: 0,
child: Image.asset(
Images.avatars[6],
fit: BoxFit.cover,
),
),
MySpacing.height(8),
MyText.bodySmall(
'${Utils.getTimeStringFromDateTime(
message.sendAt,
showSecond: false,
)}',
fontSize: 8,
muted: true,
fontWeight: 600,
),
],
),
],
);
},
separatorBuilder: (context, index) {
return MySpacing.height(12);
}),
),
Divider(height: 0),
Padding(
padding: MySpacing.all(24),
child: sendMessage(),
),
],
));
}
}