Ad

How To Return Multiple Data Via StreamController?

- 1 answer

I'm trying to fetch markers in the google map dynamically and change the marker colour, on DB update. I'm successfully manage to fetch the markers on google map but I couldn't able to listen to the marker updates in firestore correctly.

This is my profiles db structure. profiles collection contains list of profile basic details.

profiles db structure

And each profile(document) contains an attendance sub-collection, which consists of, date as document and attendance data.

attendance db structure

I fetched markers in the google map, by looping through profiles collection. Now, I'm struggling to check each profile(document) ->attendance -> date ->is_coming: true or false, if is it false I've to update the colour of the specific marker.

This is how I'm trying to listen to each attendance record.

  final StreamController<Attendance> _attendanceController =
      StreamController<Attendance>.broadcast();

  Stream checkAttendance({String member, String batch}) {
    _profileCollectionReference //profiles collection
        .document(member)
        .collection('attendance')
        .document(toDate) //date
        .snapshots()
        .forEach((snapshot) {
      var data = Attendance.fromData(
          data: snapshot.data, profileId: member, batchId: batch); //returns as Attendance type

      _attendanceController.add(data);
    });

    return _attendanceController.stream;
  }

The problem is, it just returns the last record only or overwrites previous records. This checkAttendance stream function is also running in-side a loop.

I've to listen to each attendance sub-collection constantly. I can't return as future since I've to update on live.

I can't use StreamBuilder in this case because, I'm using MVVM architecture Stacked.

I couldn't able to figure it out. Any would be appreciated.

UPDATED

This is how I'm return the markers

  final FirestoreService _firestoreService = locator<FirestoreService>();

  Map<MarkerId, Marker> _markers = <MarkerId, Marker>{};
  Map<MarkerId, Marker> get markers => _markers;

  void getMembers(Batch batch) {
    setBusy(true);

    _firestoreService.getMembers(batch.id).listen((event) { //returns the list of members assigned to a batch
      List<Profile> members = event;

      if (members != null && members.length > 0) {
        members.forEach((member) { //loop through list of members
          if (member.attendingDays.contains(toDay) && !member.onVacation) { //validation
            createAttendance(member.id, batch.id);

         //this is code part where I'm checking attendance
            _firestoreService
                .checkAttendance(member: member.id, batch: batch.id)
                .listen((attendanceEvent) { //returns list of attendance records of members
              List<Attendance> attendances = attendanceEvent;

              if (attendances != null && attendances.length > 0) {
                attendances.forEach((attendance) {
                  final MarkerId markerId = MarkerId(member.id);
                  final Marker marker = Marker(
                    markerId: markerId,
                    position: LatLng(
                      member.pickupLatLng.latitude,
                      member.pickupLatLng.longitude,
                    ),
                    icon: (attendance.isComing)
                        ? BitmapDescriptor.defaultMarkerWithHue(
                            BitmapDescriptor.hueGreen)
                        : BitmapDescriptor.defaultMarker,
                    flat: true,
                    zIndex: 2,
                    anchor: Offset(0.5, 0.5),
                    onTap: () {},
                  );

                  _markers[markerId] = marker;
                  notifyListeners();
                });
              }
            });
          }
        });
      }

      setBusy(false);
    });
  }
Ad

Answer

Actually I found a way to change the colour of the marker for my case.

As @pskink suggested I returned the Attendance data as a list.

Then I created following function.

  void checkAttendance(String member, String batch) {
    _firestoreService
        .checkAttendance(member: member, batch: batch)
        .listen((attendanceEvent) {
      List<Attendance> attendances = attendanceEvent;

      if (attendances != null && attendances.length > 0) {
        attendances.forEach((attendance) {
          final MarkerId markerId = MarkerId(attendance.profileId);
          final Marker matchedMarker = _markers[markerId];

          if (!attendance.isComing) { //validation
            final Marker newMarker = matchedMarker.copyWith(
                iconParam: BitmapDescriptor.defaultMarker);
            _markers[markerId] = newMarker;
          } else {
            final Marker newMarker = matchedMarker.copyWith(
                iconParam: BitmapDescriptor.defaultMarkerWithHue(
                  BitmapDescriptor.hueGreen));
            _markers[markerId] = newMarker;            
          }
          notifyListeners();
        });
      }
    });
  }

I already fetching the markers to google map. So, with attendance data I'm returning the profile id too. Each marker_id equals to profile id.

Therefore, what I did was I return the matched marker_id and profile id and then made a of the matched marker using .copyWith() function and the changed the icon colour according to the validation.

At last I found the solution by myself. I hoped this solution might help someone.

Ad
source: stackoverflow.com
Ad