chat screen
This commit is contained in:
@@ -0,0 +1,329 @@
|
||||
import 'package:chat_repository/chat_repository.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:injector/injector.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:prosappco/blocs/chat_bloc/chat_bloc.dart';
|
||||
import 'package:prosappco/screens/user/user_view_profile_screen.dart';
|
||||
import 'package:service_repository/service_repository.dart';
|
||||
import 'package:user_repository/user_repository.dart';
|
||||
|
||||
class ChatScreen extends StatefulWidget {
|
||||
final ServiceEntity service;
|
||||
|
||||
const ChatScreen({super.key, required this.service});
|
||||
|
||||
@override
|
||||
State<ChatScreen> createState() => _ChatScreenState();
|
||||
}
|
||||
|
||||
class _ChatScreenState extends State<ChatScreen> {
|
||||
late final ChatBloc chatBloc;
|
||||
final TextEditingController _messageController = TextEditingController();
|
||||
final FocusNode _messageFocusNode = FocusNode();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
chatBloc = Injector.appInstance.get<ChatBloc>();
|
||||
|
||||
chatBloc.add(LoadChatEvent(
|
||||
serviceId: widget.service.id!,
|
||||
userId: widget.service.userId,
|
||||
professionalId: widget.service.professionalId,
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_messageController.dispose();
|
||||
_messageFocusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Chat'),
|
||||
),
|
||||
body: BlocProvider(
|
||||
create: (context) => chatBloc,
|
||||
child: BlocBuilder<ChatBloc, ChatState>(
|
||||
builder: (context, state) {
|
||||
if (state is ChatLoaded) {
|
||||
return Column(
|
||||
children: [
|
||||
FutureBuilder(
|
||||
future: _getUserAndProfessionalInfo(widget.service),
|
||||
builder: (BuildContext context,
|
||||
AsyncSnapshot<List<dynamic>> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else {
|
||||
if (snapshot.hasError) {
|
||||
return Center(
|
||||
child: Text('Error inesperado: ${snapshot.error}'),
|
||||
);
|
||||
} else {
|
||||
final userInfo = snapshot.data![0] as MyUser;
|
||||
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||
color: const Color(0xFFD6F4FF),
|
||||
alignment: Alignment.topCenter,
|
||||
child: ListTile(
|
||||
leading: Container(
|
||||
width: 60,
|
||||
height: 60,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade300,
|
||||
shape: BoxShape.circle,
|
||||
image: userInfo.picture == null
|
||||
? null
|
||||
: DecorationImage(
|
||||
image: NetworkImage(
|
||||
userInfo.picture ?? ''),
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
child: userInfo.picture == null
|
||||
? Icon(
|
||||
CupertinoIcons.person,
|
||||
color: Colors.grey.shade400,
|
||||
size: 40,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
title: Text(
|
||||
userInfo.name ?? '',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
subtitle: const Text(
|
||||
'Rating: 5.0',
|
||||
// _disponibilidad(
|
||||
// filteredUsers[index].professionalInfo),
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: Colors.blue,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
padding: const EdgeInsets.only(top: 10),
|
||||
reverse: true,
|
||||
child: Column(
|
||||
children: _messagesList(state.chat.messages),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 15, vertical: 15),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextFormField(
|
||||
focusNode: _messageFocusNode,
|
||||
controller: _messageController,
|
||||
style: const TextStyle(color: Colors.black),
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Mensaje',
|
||||
hintStyle: TextStyle(
|
||||
color: Colors.grey[600], fontSize: 16),
|
||||
border: OutlineInputBorder(
|
||||
borderSide: const BorderSide(
|
||||
color: Colors.grey, width: 1.0),
|
||||
borderRadius: BorderRadius.circular(50)),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: const BorderSide(
|
||||
color: Colors.grey, width: 1.0),
|
||||
borderRadius: BorderRadius.circular(50)),
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 20, vertical: 15),
|
||||
filled: true,
|
||||
fillColor: Colors.grey[200],
|
||||
),
|
||||
onFieldSubmitted: (value) async {
|
||||
if (_messageController.text.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
MessageEntity message = MessageEntity(
|
||||
ownerId:
|
||||
FirebaseAuth.instance.currentUser!.uid,
|
||||
content: _messageController.text.trim(),
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
|
||||
chatBloc.add(SendMessageEvent(
|
||||
serviceId: widget.service.id!,
|
||||
message: message,
|
||||
));
|
||||
_messageController.clear();
|
||||
_messageFocusNode.requestFocus();
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
if (_messageController.text.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
MessageEntity message = MessageEntity(
|
||||
ownerId: FirebaseAuth.instance.currentUser!.uid,
|
||||
content: _messageController.text.trim(),
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
|
||||
chatBloc.add(SendMessageEvent(
|
||||
serviceId: widget.service.id!,
|
||||
message: message,
|
||||
));
|
||||
_messageController.clear();
|
||||
_messageFocusNode.requestFocus();
|
||||
},
|
||||
child: Container(
|
||||
height: 50,
|
||||
width: 50,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).primaryColor,
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
),
|
||||
child: const Center(
|
||||
child: Icon(
|
||||
Icons.send,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> _messagesList(List<MessageEntity> messages) {
|
||||
return messages
|
||||
.map(
|
||||
(e) => e.ownerId != FirebaseAuth.instance.currentUser!.uid
|
||||
? ListTile(
|
||||
title: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
margin: const EdgeInsets.only(right: 60),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 10, horizontal: 16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey.shade200,
|
||||
borderRadius: const BorderRadius.only(
|
||||
topRight: Radius.circular(20),
|
||||
bottomLeft: Radius.circular(20),
|
||||
bottomRight: Radius.circular(20),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
e.content,
|
||||
style: const TextStyle(fontSize: 16),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: Text(
|
||||
DateFormat('h:mm a').format(e.createdAt),
|
||||
style:
|
||||
const TextStyle(color: Colors.grey, fontSize: 12),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: ListTile(
|
||||
title: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Container(
|
||||
margin: const EdgeInsets.only(left: 60),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
vertical: 10,
|
||||
horizontal: 16,
|
||||
),
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFFD5EFFF),
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(20),
|
||||
bottomLeft: Radius.circular(20),
|
||||
bottomRight: Radius.circular(20),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
e.content,
|
||||
style: const TextStyle(fontSize: 16),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: Text(
|
||||
DateFormat('h:mm a').format(e.createdAt),
|
||||
style: const TextStyle(
|
||||
color: Colors.grey,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
}
|
||||
|
||||
Future<List<dynamic>> _getUserAndProfessionalInfo(
|
||||
ServiceEntity service) async {
|
||||
final userRepo = FirebaseUserRepository(FirebaseAuth.instance);
|
||||
|
||||
final MyUser? userInfo;
|
||||
|
||||
if (FirebaseAuth.instance.currentUser!.uid == service.userId) {
|
||||
userInfo = await userRepo.getMyUser(service.userId);
|
||||
} else {
|
||||
userInfo = await userRepo.getMyUser(service.professionalId);
|
||||
}
|
||||
|
||||
return [userInfo];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user