How to attach Stream data returned from Firestore stream function to flutter bloc ? how to attach this repository in bloc ?
class FirebaseChatApi{
Stream<List<ChatContactModel>>getChatContacts(){
FirebaseFirestore firestore = FirebaseFirestore.instance;
final FirebaseAuth auth = FirebaseAuth.instance;
return firestore.collection('users')
.doc(auth.currentUser!.uid)
.collection('chats')
.snapshots().asyncMap((event)async{
List<ChatContactModel>contacts = [];
for(var document in event.docs){
var chatContact = ChatContactModel.fromJson(document.data());
//var userData = await firestore.collection('users').doc(chatContact.contactId).get();
//ar user = UserModel.fromJson(userData.data()!);
contacts.add(ChatContactModel(
name: chatContact.name,
profilePic: chatContact.profilePic,
contactId: chatContact.contactId,
timeSent: chatContact.timeSent,
lastMessage: chatContact.lastMessage));
}
return contacts;
});
}
CodePudding user response:
If you use layered approach then in the infrastructure layer you can have repository class containing method:
class MyRepository implements IRepository{
@override
Stream<List<MyObject>>> watchStream() async* {
final doc = await _firestore.userDocument();
yield* doc.myCollection
.snapshots()
.map(
(snapshot) => List<MyObject>(
snapshot.documents
.map((doc) => converterIfNeeded(doc))
.toImmutableList(),
),
// do error checking here
);
}
//...
}
Then in the application layer you would have a file with a bloc
class MyBloc extends Bloc<MyEvent, MyState> {
final IRepository _repository;
MyBloc(this._repository) : super(Mytate.initial()) {
on<_WatchMessages>((_onWatchMessages));
}
void _onWatchMessages(_WatchMessages event, Emitter<MyState> emit) async {
await emit.forEach(_repository.watchMessages(),
onData: ((List<MyObject> messages) {
return state.copyWith(messages: List.from(messages));
}));
}
// ...
}
This example assumes the use of IRepository interface to get rid of application layer dependence on infrastructure layer.
It also assumes MyState class has a copyWith method which for example freezed can generate for you.
Example of MyState implementation:
@freezed
class MyState with _$MyState {
const factory MyState({required List<MyObject> messages
// other properties of state here
}) = _MyState;
factory MyState.initial() => const MyState(messages: []);
}
or something like this:
@freezed
class MyState with _$MyState {
const factory MyState.initial() = Initial;
const factory MyState.messageReceived(List<MyObject> messages) = MessageReceived;
const factory MyState.failure(Failure f) = Failure;
}
CodePudding user response:
//My Bloc
part 'chat_contact_event.dart';
part 'chat_contact_state.dart';
class ChatContactBloc extends Bloc<ChatContactEvent,ChatContactState> {
ChatContactBloc() :super(LoadingChatContactState()) {
on<WatchChatContactsEvent>(_onWatchChatContactsEvent);
}
void _onWatchChatContactsEvent(
WatchChatContactsEvent event,
Emitter<ChatContactState> emit) async {
await emit.forEach(FirebaseChatApi().getChatContacts(),
onData:(List<ChatContactModel>chatContacts){
return LoadedChatContactState(chatContacts:chatContacts);
});
}
}
//My Event
part of 'chat_contact_bloc.dart';
class ChatContactEvent extends Equatable {
const ChatContactEvent();
@override
List<Object> get props =>[];
}
class WatchChatContactsEvent extends ChatContactEvent{ }
//My State
part of 'chat_contact_bloc.dart';
class ChatContactState extends Equatable {
const ChatContactState();
@override
List<Object?> get props => [];
}
class LoadingChatContactState extends ChatContactState{}
class LoadedChatContactState extends ChatContactState{
final List<ChatContactModel>chatContacts;
const LoadedChatContactState( { required this.chatContacts,});
@override
List<Object?> get props => [chatContacts];
}
//My Widget
Widget build(BuildContext context) {
return Scaffold(
extendBody: false,
backgroundColor: Colors.transparent,
appBar: AppBar(
backgroundColor: Colors.black,
centerTitle: true,
title: const Text('Messages',style: TextStyle(color:Colors.white),),
),
body: BlocBuilder<ChatContactBloc,ChatContactState>(
builder: (context, state) {
if(state is LoadingChatContactState){
return const Center(
child: CircularProgressIndicator());
}
else if(state is LoadedChatContactState){
return ListView.builder(
shrinkWrap: true,
itemCount: state.chatContacts.length,
itemBuilder: (context, index) {
var chatContactData = state.chatContacts[index];
return Column(
children: [
InkWell(
onTap: () {
},
child: Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: ListTile(
title: Text(
chatContactData.name,
//'Janam',
style: const TextStyle(
fontSize: 18,
),
),
subtitle: Padding(
padding: const EdgeInsets.only(top: 6.0),
child: Text(
//chatContactData.lastMessage
'LastMessage',
style: const TextStyle(fontSize: 15),
),
),
leading: CircleAvatar(
backgroundImage: NetworkImage(
// chatContactData.profilePic
'',
),
radius: 30,
),
trailing: Text(
'12:04',
//DateFormat.Hm().format(chatContactData.timeSent),
style: const TextStyle(
color: Colors.grey,
fontSize: 13,
),
),
),
),
),
const Divider(color: dividerColor, indent: 85),
],
);
},
);
}
else{
return Container();
}
}
)
);
}