【问题标题】:Firebase query Stream with filters not updating when document is added: Flutter添加文档时过滤器未更新的Firebase查询流:Flutter
【发布时间】:2022-01-03 07:38:04
【问题描述】:

我正在开发我的颤振应用程序的聊天部分。我有一个 chat_messages 集合,其中包含用户为应用程序中的所有聊天发送的所有消息。下面是一个 chat_messages 文档的结构:

这里user 是消息的发送者。我想显示特定用户的未读消息的数量(其中message.seen==false),因此我使用下面的查询来获取用户看不到的所有消息的串,并且我收听该流中的任何新消息发送的消息:

    unreadMessagesStream = queryChatMessagesRecord(queryBuilder: (query) 
{
  return query
      .where('chat_users', arrayContains: currentUserReference)
      .where('user', isNotEqualTo: currentUserReference)
      .where('seen', isEqualTo: false);
});

unreadMessagesStream.listen((msgs) {
  if (mounted)
    setState(() {
      unreadMessagesCount = msgs?.length ?? 0;
    });
});

不幸的是,此流仅在应用运行时产生一次值,但随后在发送任何新消息时,流中不会接收到新值并且未读消息的数量保持不变。

注意:如果我删除过滤器并查询整个集合,则一切正常。

【问题讨论】:

  • 我没有那种架构。对我来说,每个用户都有他们最后一次阅读聊天的时间戳,每条消息也有一个时间戳。因此,只需获取大于特定时间戳用户的所有时间戳消息的计数。是不是更简单?
  • 你的方法确实很有趣

标签: firebase flutter dart


【解决方案1】:

我给你一个我的代码的 sn-p 以便更快地完成它:下面的代码只是针对每个用户。它是聊天的子集合。因此,用户可以为每个聊天设置一个 chatMembre。

import 'package:cloud_firestore/cloud_firestore.dart';

enum IsDoing { reading, notReading, writing, recording }

class ChatMembre {
  final String id;
  final DateTime lastReading;
  final DateTime lastReceived;
  final IsDoing isDoing;
  final bool hasSubscribeToTopic;

  ChatMembre(
      {required this.id,
      required this.lastReading,
      required this.lastReceived,
      required this.isDoing,
      required this.hasSubscribeToTopic});



  Map<String, dynamic> toMap() {
    return {
      'id': id,
      'lastReading': lastReading == DateTime.now()
          ? FieldValue.serverTimestamp()
          : DateTime.now(),
      'lastReceived': lastReceived == DateTime.now()
          ? FieldValue.serverTimestamp()
          : DateTime.now(),
      'isDoing':
          isDoing.toString().substring(isDoing.toString().indexOf(".") + 1),
      'isSubscribeToTopic': hasSubscribeToTopic
    };
  }

  factory ChatMembre.fromMap(Map<String, dynamic>? map) {
    if (map == null || map.isEmpty) {
      return ChatMembre(
          id: '',
          lastReading: DateTime.now(),
          lastReceived: DateTime.now(),
          hasSubscribeToTopic: false,
          isDoing: IsDoing.notReading);
    }

    IsDoing isDoing;

    switch (map["isDoing"]) {
      case "reading":
        isDoing = IsDoing.reading;
        break;
      case "writing":
        isDoing = IsDoing.writing;
        break;
      case "recording":
        isDoing = IsDoing.recording;
        break;
      default:
        isDoing = IsDoing.notReading;
        break;
    }

    return ChatMembre(
        id: (map['id'] ?? '') as String,
        lastReading:
            ((map['lastReading'] ?? Timestamp.now()) as Timestamp).toDate(),
        lastReceived:
            ((map['lastReceived'] ?? Timestamp.now()) as Timestamp).toDate(),
        isDoing: isDoing,
        hasSubscribeToTopic: (map['isSubscribeToTopic'] ?? false) as bool);
  }

  @override
  String toString() {
    return 'ChatMembre{id: $id, lastReading: $lastReading, lastReceived: $lastReceived, isDoing: $isDoing, hasSubscribeToTopic: $hasSubscribeToTopic}';
  }
}

下面是查找聊天页面的状态。

import 'dart:convert';

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:customer/constants/credentials.dart';
import 'package:customer/constants/firestore_path.dart';
import 'package:customer/domain/repositories/my_chat_repository.dart';
import 'package:customer/services/firestore_service.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:http/http.dart' as http;

class ChatRoomLifeCycle extends StatefulWidget {
  final Widget child;
  final MyChatRepository chatRepo;
  final String chatId;
  final String? token;
  final String? idTo;
  final Timestamp? lastReceivedOfFriend;

  const ChatRoomLifeCycle(
      {Key? key,
      required this.chatId,
      required this.chatRepo,
      required this.child,
      this.token,
      this.idTo,
      this.lastReceivedOfFriend})
      : super(key: key);

  @override
  _ChatRoomLifeCycleState createState() => _ChatRoomLifeCycleState();
}

class _ChatRoomLifeCycleState extends State<ChatRoomLifeCycle>
    with WidgetsBindingObserver {
  late GlobalKey<AnimatedListState> listKey;
  bool hasSentFcm = false;

  @override
  void initState() {
    super.initState();
    sendPushMessage();
    WidgetsBinding.instance!.addObserver(this);
    widget.chatRepo.setIsReading();
  }

  @override
  void dispose() {
    widget.chatRepo.setIsNotReading(isFromDispose: true);


    WidgetsBinding.instance!.removeObserver(this);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return widget.child;
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    switch (state) {
      case AppLifecycleState.paused:
        widget.chatRepo.setIsNotReading();
        break;
      case AppLifecycleState.resumed:
        widget.chatRepo.setIsReading();
        break;
      case AppLifecycleState.inactive:
        widget.chatRepo.setIsNotReading();
        break;
      case AppLifecycleState.detached:
        widget.chatRepo.setIsNotReading();
        break;
    }
  }

  Future<void> sendPushMessage() async {
    if (hasSentFcm || widget.idTo == null || widget.token == null) {
      return;
    }
    FirestoreService.instance.updateData(
        path: MyPath.myUserStatus(uid: widget.idTo!), data: {'isLogin': false});

    try {
      await http
          .post(
            Uri.parse('https://fcm.googleapis.com/fcm/send'),
            headers: <String, String>{
              'Content-Type': 'application/json',
              'Authorization': 'key=$serverToken',
            },
            body: constructFCMPayload(widget.token!),
          )
          .catchError((onError) {});

      hasSentFcm = true;
    } catch (e) {
      Fluttertoast.showToast(msg: e.toString());
    }
  }

  // Crude counter to make messages unique

  /// The API endpoint here accepts a raw FCM payload for demonstration purposes.
  String constructFCMPayload(String token) {
    return jsonEncode(<String, dynamic>{
      'data': <String, dynamic>{
        'test': 'check online',
        'chatId': widget.chatId,
        'idTo': widget.idTo
      },
      'to': token,
    });
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-24
    • 1970-01-01
    • 2019-01-26
    • 1970-01-01
    • 1970-01-01
    • 2020-01-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多