У меня 2 потока
Stream<List<GroupModel>> groupStream() {
final CollectionReference groupCollection = fireStore.collection('groups');
return groupCollection
.where('members.${user.id}', isEqualTo: true)
.snapshots()
.map((snapshot) => snapshot.documents.map((document) => GroupModel.fromFirestore(document)).toList());
}
Stream<List<GroupSubscriptionModel>> groupSubscriptionsStream(List<GroupModel> groups) {
final chunks = chunkSizeCollection(groups, 10);
List<Stream<List<GroupSubscriptionModel>>> streams = List<Stream<List<GroupSubscriptionModel>>>();
chunks.forEach((chunck) => streams.add(fireStore
.collection('users/${userID}/userGroupSubscriptions')
.where(FieldPath.documentId, whereIn: chunck)
.snapshots()
.map((snapshot) =>
snapshot.documents.map((document) => GroupSubscriptionModel.fromFirestore(document)).toList())));
return ZipStream(streams, (value) => value.last);
}
Я хочу получить все группы, а затем от пользователя получить подписки, которые в основном говорят, подписаны ли пользователи на группу или нет. Затем в моем пользовательском интерфейсе я переключаю значок в зависимости от того, подписан пользователь или нет.
Моя проблема в том, что мой groupSubscriptionsStream
зависит от идентификаторов из групп, чтобы получить соответствующий документ. Потому что я не могу просто транслировать все документы в коллекции. Если бы я мог, у меня не было бы никаких проблем.
Я использую blo c с поставщиком, чтобы предоставить мои контроллеры потока моему виджету. Но моему StreamSubscriptionsBloc
нужен List<GroupModel>
, чтобы добавить поток к его контроллеру
class GroupSubscriptionsBloc{
final StreamController<List<GroupSubscriptionModel>> _controller = StreamController<List<GroupSubscriptionModel>>();
Stream<List<GroupSubscriptionModel>> get stream => _controller.stream;
GroupSubscriptionsBloc(DatabaseService database, List<GroupModel> groups)
{
_controller.addStream(database.groupSubscriptionsStream(groups));
}
void dispose(){
_controller.close();
}
}
Итак, в виджете у меня есть метод stati c, который предоставляет два blo c к виджету
static Widget create(BuildContext context) {
final database = Provider.of<DatabaseService>(context);
return MultiProvider(
providers: [
Provider(
create: (_) => GroupBloc(database),
dispose: (BuildContext context, GroupBloc bloc) => bloc.dispose(),
),
Provider(
create: (_) => GroupSubscriptionsBloc(database, null),
dispose: (BuildContext context, GroupSubscriptionsBloc bloc) => bloc.dispose(),
),
],
child: TheGroupOverviewPage(),
);
}
Но, как вы можете видеть, в настоящее время я передаю null подпискам blo c, потому что у меня нет групп. Поэтому я не могу добавить поток к контроллеру.
Но я действительно хочу использовать оба блока в виджете TheGroupOverviewPage
, потому что не имеет смысла делать это в другом виджете.
Итак, вопрос в том, как мне получить это List<GroupModel>
?
Дело в том, что мне даже не понадобились бы два потока, если бы я мог каким-то образом объединить два потока и сопоставить их с моим GroupModel
, чтобы я переключил isSubscribed на true.
class GroupModel
{
final String _id;
final String _displayName;
final Map<String, bool> _members;
final Map<String, bool> _admins;
bool isSubscribed = false;
String get id => _id;
String get displayName => _displayName;
Map<String, bool> get members => _members;
Map<String, bool> get admins => _admins;
GroupModel._internal(this._id, this._displayName, this._members, this._admins);
factory GroupModel.fromFirestore(DocumentSnapshot document)
{
return GroupModel._internal(
document.documentID ?? '',
document['displayName'] ?? '',
document['members'] != null ? Map.from(document['members']) : Map<String,bool>(),
document['admins'] != null ? Map.from(document['admins']) : Map<String,bool>(),
);
}
}
Я знаю, что вы можете комбинировать потоки, но в этом случае второй поток зависит от первого потока. Так это вообще вариант? Это имело бы наибольший смысл, потому что он выводил бы List<GroupModel>
, где isSubscribed устанавливается вторым потоком. И я могу сохранить все групповые группы, связанные в одном потоке.
Вот как мне сейчас нужно создавать потоки в TheGroupOverview
виджете
body: StreamBuilder(
initialData: List<GroupModel>(),
stream: groupBloc.groupStream,
builder: (BuildContext context, AsyncSnapshot<List<GroupModel>> groupsSnapshot) {
return ConditionalWidget(
condition: groupsSnapshot.connectionState == ConnectionState.active,
widgetTrue: StreamBuilder(
initialData: List<GroupSubscriptionModel>(),
stream: groupSubscriptionsBloc.stream,
builder: (BuildContext context, AsyncSnapshot<List<GroupSubscriptionModel>> subscriptionSnapshot) {
groupsSnapshot.data?.forEach((group) => group.isSubscribed =
subscriptionSnapshot.data?.any((subscription) => subscription.belongsTo(group)));
return ConditionalWidget(
condition: subscriptionSnapshot.connectionState == ConnectionState.active,
widgetTrue: Builder(
builder: (BuildContext context) {
return GroupList(
groupsSnapshot.data,
padding: const EdgeInsets.only(top: 25.0, left: 20.0, right: 20.0),
onNotificationIconTap: _onGroupNotificationIconTap,
);
},
),
widgetFalse: PlatformCircularProgressIndicator(),
);
},
),
widgetFalse: PlatformCircularProgressIndicator(),
);
},
),
Edit - WIP
return groupCollection
.where('members.${user.id}', isEqualTo: true)
.snapshots()
.flatMap((groups) => _groupSubscriptionsStream(groups) , //here should merging happen?));
}
Stream<QuerySnapshot> _groupSubscriptionsStream(QuerySnapshot groups) {
final chunks = chunkSizeCollection(groups.documents.map((group) => group.documentID).toList(), 10);
List<Stream<QuerySnapshot>> streams = List<Stream<QuerySnapshot>>();
chunks.forEach((chunck) => streams.add(fireStore
.collection(APIRoutes.userSubscriptions(user.id))
.where(FieldPath.documentId, whereIn: chunck)
.snapshots()));
return ZipStream(streams, (value) => value.last);