chat screen
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:chat_repository/chat_repository.dart';
|
||||
|
||||
part 'chat_event.dart';
|
||||
part 'chat_state.dart';
|
||||
|
||||
class ChatBloc extends Bloc<ChatEvent, ChatState> {
|
||||
final FirebaseChatRepository _chatRepository;
|
||||
|
||||
ChatBloc({
|
||||
required FirebaseChatRepository chatRepository,
|
||||
}) : _chatRepository = chatRepository,
|
||||
super(ChatInitial()) {
|
||||
on<LoadChatEvent>(_onLoadChatEvent);
|
||||
on<SendMessageEvent>(_onSendMessageEvent);
|
||||
}
|
||||
|
||||
void _onLoadChatEvent(LoadChatEvent event, Emitter<ChatState> emit) async {
|
||||
bool autoCreate = true;
|
||||
|
||||
try {
|
||||
emit(ChatLoading());
|
||||
|
||||
Stream<ChatEntity?> chatStream = _chatRepository.getChatById(
|
||||
event.serviceId,
|
||||
);
|
||||
|
||||
await for (var chat in chatStream) {
|
||||
if (chat == null) {
|
||||
if (autoCreate) {
|
||||
chat = await _chatRepository.createNewChat(
|
||||
event.serviceId,
|
||||
event.userId,
|
||||
event.professionalId,
|
||||
);
|
||||
|
||||
autoCreate = false;
|
||||
} else {
|
||||
emit(ChatFailure());
|
||||
}
|
||||
} else {
|
||||
emit(ChatLoaded(chat: chat));
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
emit(ChatFailure());
|
||||
}
|
||||
}
|
||||
|
||||
void _onSendMessageEvent(
|
||||
SendMessageEvent event, Emitter<ChatState> emit) async {
|
||||
try {
|
||||
await _chatRepository.sendMessage(event.serviceId, event.message);
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
emit(ChatFailure());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
part of 'chat_bloc.dart';
|
||||
|
||||
abstract class ChatEvent extends Equatable {
|
||||
const ChatEvent();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class LoadChatEvent extends ChatEvent {
|
||||
final String serviceId;
|
||||
final String userId;
|
||||
final String professionalId;
|
||||
|
||||
const LoadChatEvent({
|
||||
required this.serviceId,
|
||||
required this.userId,
|
||||
required this.professionalId,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object> get props => [
|
||||
serviceId,
|
||||
userId,
|
||||
professionalId,
|
||||
];
|
||||
}
|
||||
|
||||
class SendMessageEvent extends ChatEvent {
|
||||
final String serviceId;
|
||||
final MessageEntity message;
|
||||
|
||||
const SendMessageEvent({
|
||||
required this.message,
|
||||
required this.serviceId,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object> get props => [
|
||||
serviceId,
|
||||
message,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
part of 'chat_bloc.dart';
|
||||
|
||||
class ChatState extends Equatable {
|
||||
const ChatState();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class ChatInitial extends ChatState {}
|
||||
|
||||
class ChatLoading extends ChatState {}
|
||||
|
||||
class ChatLoaded extends ChatState {
|
||||
final ChatEntity chat;
|
||||
|
||||
const ChatLoaded({required this.chat});
|
||||
|
||||
@override
|
||||
List<Object> get props => [chat];
|
||||
}
|
||||
|
||||
class ChatFailure extends ChatState {}
|
||||
@@ -1,9 +1,11 @@
|
||||
import 'package:chat_repository/chat_repository.dart';
|
||||
import 'package:firebase_auth/firebase_auth.dart';
|
||||
import 'package:injector/injector.dart';
|
||||
import 'package:profession_repository/profession_repository.dart';
|
||||
import 'package:professional_repository/professional_repository.dart';
|
||||
import 'package:prosappco/blocs/auth_bloc/auth_bloc.dart';
|
||||
import 'package:prosappco/blocs/authentication_bloc/authentication_bloc.dart';
|
||||
import 'package:prosappco/blocs/chat_bloc/chat_bloc.dart';
|
||||
import 'package:prosappco/blocs/my_user_bloc/my_user_bloc.dart';
|
||||
import 'package:prosappco/blocs/professional_bloc/professional_bloc.dart';
|
||||
import 'package:prosappco/blocs/professional_list_bloc/professional_list_bloc.dart';
|
||||
@@ -35,6 +37,7 @@ class AppDI {
|
||||
|
||||
injector.registerSingleton(() => FirebaseProfessionalRepository());
|
||||
injector.registerSingleton(() => FirebaseServiceRepository());
|
||||
injector.registerSingleton(() => FirebaseChatRepository());
|
||||
|
||||
injector.registerSingleton<AuthenticationBloc>((() =>
|
||||
AuthenticationBloc(myUserRepository: injector.get<UserRepository>())));
|
||||
@@ -73,6 +76,10 @@ class AppDI {
|
||||
injector.get<FirebaseProfessionalRepository>()),
|
||||
);
|
||||
|
||||
injector.registerDependency<ChatBloc>(() => ChatBloc(
|
||||
chatRepository: injector.get<FirebaseChatRepository>(),
|
||||
));
|
||||
|
||||
injector.registerDependency<ServiceBloc>(
|
||||
() => ServiceBloc(
|
||||
serviceRepository: injector.get<FirebaseServiceRepository>(),
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import 'package:intl/intl.dart';
|
||||
import 'package:professional_repository/professional_repository.dart';
|
||||
import 'package:prosappco/blocs/service_bloc/service_bloc.dart';
|
||||
import 'package:prosappco/components/general_secondary_button.dart';
|
||||
import 'package:prosappco/screens/chat/chat_screen.dart';
|
||||
import 'package:service_repository/service_repository.dart';
|
||||
import 'package:setting_repository/setting_repository.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
@@ -55,8 +56,7 @@ class _ProfessionalServiceScreenState extends State<ProfessionalServiceScreen> {
|
||||
final service = state.service;
|
||||
return FutureBuilder(
|
||||
future: _getUserAndProfessionalInfo(service),
|
||||
builder: (BuildContext context,
|
||||
AsyncSnapshot<List<dynamic>> snapshot) {
|
||||
builder: (BuildContext context, AsyncSnapshot<List<dynamic>> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else {
|
||||
@@ -274,7 +274,16 @@ class _ProfessionalServiceScreenState extends State<ProfessionalServiceScreen> {
|
||||
),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {},
|
||||
onPressed: () {
|
||||
if (service.id != null) {
|
||||
Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (context) => ChatScreen(service: service),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
foregroundColor: const Color(0xFF2BA4EC),
|
||||
backgroundColor: Colors.white,
|
||||
@@ -661,8 +670,7 @@ class _ProfessionalServiceScreenState extends State<ProfessionalServiceScreen> {
|
||||
return '\$${formatter.format(number)}';
|
||||
}
|
||||
|
||||
Future<List<dynamic>> _getUserAndProfessionalInfo(
|
||||
ServiceEntity service) async {
|
||||
Future<List<dynamic>> _getUserAndProfessionalInfo(ServiceEntity service) async {
|
||||
final userRepo = FirebaseUserRepository(FirebaseAuth.instance);
|
||||
final userInfo = await userRepo.getMyUser(service.userId);
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:injector/injector.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:professional_repository/professional_repository.dart';
|
||||
import 'package:prosappco/blocs/service_bloc/service_bloc.dart';
|
||||
import 'package:prosappco/screens/chat/chat_screen.dart';
|
||||
import 'package:prosappco/components/general_secondary_button.dart';
|
||||
import 'package:service_repository/service_repository.dart';
|
||||
import 'package:setting_repository/setting_repository.dart';
|
||||
@@ -238,7 +239,6 @@ class _UserServiceScreenState extends State<UserServiceScreen> {
|
||||
|
||||
customMapButton(service),
|
||||
|
||||
|
||||
// ListTile(
|
||||
// leading: const Icon(Icons.near_me),
|
||||
// title: Text(
|
||||
@@ -423,7 +423,14 @@ class _UserServiceScreenState extends State<UserServiceScreen> {
|
||||
),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {},
|
||||
onPressed: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
CupertinoPageRoute(
|
||||
builder: (context) => ChatScreen(service: service),
|
||||
),
|
||||
);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
foregroundColor: const Color(0xFF2BA4EC),
|
||||
backgroundColor: Colors.white,
|
||||
|
||||
@@ -27,19 +27,6 @@ class UserViewProfileScreen extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
// Container(
|
||||
// decoration: BoxDecoration(
|
||||
// gradient: LinearGradient(
|
||||
// colors: [
|
||||
// Colors.blue.withOpacity(1),
|
||||
// Colors.blue.withOpacity(0),
|
||||
// Colors.blue.withOpacity(0),
|
||||
// ],
|
||||
// begin: Alignment.bottomCenter,
|
||||
// end: Alignment.topCenter,
|
||||
// ),
|
||||
// ),
|
||||
}
|
||||
|
||||
Stack buildTop() {
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
library chat_repository;
|
||||
|
||||
export 'src/entities/entities.dart';
|
||||
export 'src/repositories/firebase_chat_repository.dart';
|
||||
@@ -0,0 +1,49 @@
|
||||
import 'package:chat_repository/src/entities/entities.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
class ChatEntity extends Equatable {
|
||||
final String? id;
|
||||
final String userId;
|
||||
final String professionalId;
|
||||
final List<MessageEntity> messages;
|
||||
|
||||
const ChatEntity({
|
||||
required this.id,
|
||||
required this.userId,
|
||||
required this.professionalId,
|
||||
required this.messages,
|
||||
});
|
||||
|
||||
static ChatEntity fromDocument(Map<String, dynamic> doc) {
|
||||
return ChatEntity(
|
||||
id: doc['id'] as String,
|
||||
userId: doc['user_id'] as String,
|
||||
professionalId: doc['professional_id'] as String,
|
||||
messages: (doc['messages'] as List)
|
||||
.map((e) => MessageEntity.fromDocument(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toDocument() {
|
||||
return {
|
||||
'id': id,
|
||||
'user_id': userId,
|
||||
'professional_id': professionalId,
|
||||
'messages': messages.map((e) => e.toDocument()).toList(),
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [id, userId, professionalId, messages];
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '''ChatEntity{
|
||||
id: $id,
|
||||
userId: $userId,
|
||||
professionalId: $professionalId,
|
||||
messages: $messages
|
||||
}''';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export '/src/entities/chat_entity.dart';
|
||||
export '/src/entities/message_entity.dart';
|
||||
@@ -0,0 +1,45 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
class MessageEntity extends Equatable {
|
||||
final String ownerId;
|
||||
final String content;
|
||||
final DateTime createdAt;
|
||||
|
||||
const MessageEntity({
|
||||
required this.ownerId,
|
||||
required this.content,
|
||||
required this.createdAt,
|
||||
});
|
||||
|
||||
static MessageEntity fromDocument(Map<String, dynamic> doc) {
|
||||
return MessageEntity(
|
||||
ownerId: doc['owner_id'] as String,
|
||||
content: doc['content'] as String,
|
||||
createdAt: DateTime.parse(doc['created_at'] as String),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toDocument() {
|
||||
return {
|
||||
'owner_id': ownerId,
|
||||
'content': content,
|
||||
'created_at': createdAt.toIso8601String(),
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
ownerId,
|
||||
content,
|
||||
createdAt,
|
||||
];
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return '''MessageEntity{
|
||||
ownerId: $ownerId,
|
||||
content: $content,
|
||||
createdAt: $createdAt
|
||||
}''';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:chat_repository/chat_repository.dart';
|
||||
import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
|
||||
class FirebaseChatRepository {
|
||||
final chatCollection = FirebaseFirestore.instance.collection('chats');
|
||||
|
||||
Stream<ChatEntity?> getChatById(String chatId) {
|
||||
return chatCollection.doc(chatId).snapshots().map((snapshot) {
|
||||
try {
|
||||
if (snapshot.exists) {
|
||||
return ChatEntity.fromDocument(snapshot.data()!);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<ChatEntity> createNewChat(
|
||||
String chatId, String userId, String professionalId) async {
|
||||
ChatEntity chat = ChatEntity(
|
||||
id: chatId,
|
||||
userId: userId,
|
||||
professionalId: professionalId,
|
||||
messages: const [],
|
||||
);
|
||||
|
||||
await chatCollection.doc(chatId).set(chat.toDocument());
|
||||
|
||||
return chat;
|
||||
}
|
||||
|
||||
sendMessage(String chatId, MessageEntity message) {
|
||||
chatCollection.doc(chatId).update({
|
||||
'messages': FieldValue.arrayUnion([message.toDocument()])
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
_flutterfire_internals:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _flutterfire_internals
|
||||
sha256: "4eec93681221723a686ad580c2e7d960e1017cf1a4e0a263c2573c2c6b0bf5cd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.25"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.11.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: boolean_selector
|
||||
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: characters
|
||||
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: clock
|
||||
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
cloud_firestore:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: cloud_firestore
|
||||
sha256: "31cfa4d65d6e9ea837234fffe121304034c30c9214c06207b4a35867e3757900"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.15.8"
|
||||
cloud_firestore_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cloud_firestore_platform_interface
|
||||
sha256: a0097a26569b015faf8142e159e855241609ea9a1738b5fd1c40bfe8411b41a0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.9"
|
||||
cloud_firestore_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cloud_firestore_web
|
||||
sha256: ed680ece29a5750985119c09cdc276b460c3a2fa80e8c12f9b7241f6b4a7ca16
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.10.8"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.18.0"
|
||||
equatable:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: equatable
|
||||
sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.5"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
firebase_core:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: firebase_core
|
||||
sha256: "53316975310c8af75a96e365f9fccb67d1c544ef0acdbf0d88bbe30eedd1c4f9"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.27.0"
|
||||
firebase_core_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_core_platform_interface
|
||||
sha256: c437ae5d17e6b5cc7981cf6fd458a5db4d12979905f9aafd1fea930428a9fe63
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.0"
|
||||
firebase_core_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: firebase_core_web
|
||||
sha256: c8e1d59385eee98de63c92f961d2a7062c5d9a65e7f45bdc7f1b0b205aab2492
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.11.5"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: flutter_lints
|
||||
sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.3"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_web_plugins:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.7"
|
||||
lints:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: lints
|
||||
sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.16"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.5.0"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.10.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path
|
||||
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.8.3"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.8"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_span
|
||||
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.10.0"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.1"
|
||||
stream_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_channel
|
||||
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: string_scanner
|
||||
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.1"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_math
|
||||
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web
|
||||
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.0"
|
||||
sdks:
|
||||
dart: ">=3.2.0 <4.0.0"
|
||||
flutter: ">=3.3.0"
|
||||
@@ -0,0 +1,25 @@
|
||||
name: chat_repository
|
||||
description: Dart package for the chat repository.
|
||||
publish_to: 'none'
|
||||
|
||||
version: 1.0.11+11
|
||||
|
||||
environment:
|
||||
sdk: ">=2.19.3 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
equatable: ^2.0.5
|
||||
|
||||
# Firebase
|
||||
cloud_firestore: ^4.15.4
|
||||
firebase_core: ^2.25.4
|
||||
|
||||
dev_dependencies:
|
||||
flutter_lints: ^2.0.0
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
@@ -2,8 +2,7 @@ import 'package:cloud_firestore/cloud_firestore.dart';
|
||||
import 'package:service_repository/service_repository.dart';
|
||||
|
||||
class FirebaseServiceRepository {
|
||||
final serviceCollection =
|
||||
FirebaseFirestore.instance.collection('services v2');
|
||||
final serviceCollection = FirebaseFirestore.instance.collection('services');
|
||||
|
||||
Future<String> createService(ServiceEntity entity) async {
|
||||
DocumentReference<Map<String, dynamic>> docRef =
|
||||
|
||||
@@ -89,6 +89,13 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
chat_repository:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "packages/chat_repository"
|
||||
relative: true
|
||||
source: path
|
||||
version: "1.0.11+11"
|
||||
city_repository:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
||||
@@ -56,6 +56,8 @@ dependencies:
|
||||
path: packages/user_repository
|
||||
city_repository:
|
||||
path: packages/city_repository
|
||||
chat_repository:
|
||||
path: packages/chat_repository
|
||||
setting_repository:
|
||||
path: packages/setting_repository
|
||||
professional_repository:
|
||||
|
||||
Reference in New Issue
Block a user