Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

チャット機能の実装 #44

Closed
kosukesaigusa opened this issue Jul 17, 2023 · 5 comments
Closed

チャット機能の実装 #44

kosukesaigusa opened this issue Jul 17, 2023 · 5 comments
Assignees
Labels
1. 機能開発 機能開発

Comments

@kosukesaigusa
Copy link
Owner

概要

UI はここ:packages/mottai_flutter_app/lib/chat/ui/chat_room.dart

モデルはここ:packages/mottai_flutter_app/lib/chat/chat_room.dart

に実装する。

UI は主に

  • 左側:相手の画像、名前、メッセージ、送信日時
  • 右側:自分のメッセージ、送信日時、既読 or 未読

を表示する。

この記事とサンプルリポジトリも一部参考にして、チャット機能を実装する(さらに改善してほしい)。

要件と改善してほしいポイントとしては

  • 上記の記事・サンプルリポジトリと同様に、チャットルームを開いたあとのチャットはリアルタイム取得、過去のメッセージは無限スクロールで 10 件ずつ順次取得できるようにする
  • AsyncNotifier と build メソッドをうまく使って初期表示をもっとうまくやる
  • 10 件ずつ取得する処理で最後に読んだ QueryDocumentSnapshot を渡しているところを改善してほしい。アプリは Cloud Firestore のことを知りたくないので、最後に読んだ ドキュメント ID などを渡せば良いようにしてほしい (参考:https://github.com/KosukeSaigusa/flutter-infinite-scroll-chat/blob/204c6909b546cd3023fcd083de4e7f30881a5578/lib/repositories/chat.dart#L62)

一応ドキュメントモデルには、「システム」からのメッセージの余地も入れているがいまは無視して OK。

余裕があれば

  • 相手の最後に読んだ日時を取得する StreamProvider
  • 自分の最後に読んだ日時を更新するメソッド

も実装すると未既読管理機能まで完成するので取り組む。できなれば「既読」or「未読」は固定値で表示しておく。

方針・要件・詳細・完了の定義など

  • 上記の実装が済んで、パフォーマンスの問題なくチャットが行えること

補足

着手時には、#mottai-app-issues チャンネルにこの Issue を貼り付ける。

また、そうしたければ、要件の整理や進捗のつぶやきのようなことをそのスレッドに書く。Issue の内容や仕様に関する説明や認識合わせが必要な場合や、ペアプロを希望する場合はそのスレッド内で、然るべき人にメンションして話を進める。

@kosukesaigusa kosukesaigusa added the 1. 機能開発 機能開発 label Jul 17, 2023
@Muhyun-Kim Muhyun-Kim self-assigned this Jul 17, 2023
@RikitoNoto RikitoNoto assigned RikitoNoto and unassigned Muhyun-Kim Jul 17, 2023
@Muhyun-Kim Muhyun-Kim self-assigned this Jul 17, 2023
@kosukesaigusa
Copy link
Owner Author

@Muhyun-Kim

参考:

https://firebase.google.com/docs/firestore/query-data/query-cursors

10 件ずつ取得する処理で最後に読んだ QueryDocumentSnapshot を渡しているところを改善してほしい。アプリは Cloud Firestore のことを知りたくないので、最後に読んだ ドキュメント ID などを渡せば良いようにしてほしい

調べてみて、上の要件が難しかったら相談してください!

@Muhyun-Kim
Copy link
Collaborator

@kosukesaigusa

わかりました!
無限スクロール実装するための参考資料ですよね?

@Muhyun-Kim
Copy link
Collaborator

課題

  • まだ送信者のプロフィール画像が実際のユーザーの画像になっていない
  • 既読・未読の実装はされていない
  • UI が仮である

@kosukesaigusa
Copy link
Owner Author

実際のユーザーの画像になっていない

これに関しては、#36 の Issue で汎用的な画像ウィジェットを作ってもらうので最終的にはそれにします。が、待つのは時間がもったいないので、とりあえず Image.network などでかんたんに実装してもらうで良いです!

既読・未読の実装はされていない

既読・未読には readStatus ドキュメントを読み込んだり更新したりして実現します。おそらく現在のドキュメントモデルでいけるはずなので考えてみてください!(もちろん質問相談してもらって良いです!)

@Muhyun-Kim
Copy link
Collaborator

@kosukesaigusa

/// ファイル名:packages/mottai_flutter_app/lib/chat/read_status.dart
class ReadStatusRepository {
  final _query = ReadStatusQuery();

  /// 指定したチャットルーム ([chatRoomId])、ユーザー ID ([userId]) の [ReadStatus]
  /// を取得する。
  Stream<ReadReadStatus?> subscribeReadStatus({
    required String chatRoomId,
    required String userId,
  })=> _query.subscribeDocument(
    chatRoomId: chatRoomId,
    readStatusId: userId,
  );

  /// 指定したチャットルーム ([chatRoomId])、ユーザー ID ([userId]) の [ReadStatus]
  /// を現在のサーバ時刻で更新する。
  Future<void> setLastReadAt({
    required String chatRoomId,
    required String userId,
  }) =>
      _query.set(
        chatRoomId: chatRoomId,
        readStatusId: userId,
        createReadStatus: const CreateReadStatus(),
      );
}
///ファイル名:packages/mottai_flutter_app/lib/chat/read_status.dart
final readStatusProvider =
    Provider.family.autoDispose<DateTime?, ReadChatRoom>((ref, readChatRoom) {
  final readStatus =
      ref.watch(readStatusStreamProvider(readChatRoom)).valueOrNull;
  return readStatus?.lastReadAt.dateTime;
});

final readStatusStreamProvider =
    StreamProvider.family.autoDispose<ReadReadStatus?, ReadChatRoom>(
  (ref, readChatRoom) {
    final userMode = ref.watch(userModeStateProvider);
    switch (userMode) {
      case UserMode.worker:
        return ref.watch(readStatusRepositoryProvider).subscribeReadStatus(
              chatRoomId: readChatRoom.chatRoomId,
              userId: readChatRoom.hostId,
            );
      case UserMode.host:
        return ref.watch(readStatusRepositoryProvider).subscribeReadStatus(
              chatRoomId: readChatRoom.chatRoomId,
              userId: readChatRoom.workerId,
            );
    }
  },
);

/// 指定した[ReadStatus] の最終既読時間を返す [Provider]
/// 最終既読時間を読み込みできなかった場合は

final readStatusServiceProvider = Provider.autoDispose<ReadStatusService>(
  (ref) => ReadStatusService(
    readStatusRepository: ref.watch(readStatusRepositoryProvider),
  ),
);

class ReadStatusService {
  const ReadStatusService({required ReadStatusRepository readStatusRepository})
      : _readStatusRepository = readStatusRepository;

  final ReadStatusRepository _readStatusRepository;

  /// 指定したチャットルーム ([chatRoomId])、ユーザー ID ([userId]) の [ReadStatus]
  /// を取得する。
  Stream<ReadReadStatus?> subscribeReadStatus({
    required String chatRoomId,
    required String userId,
  }) =>
      _readStatusRepository.subscribeReadStatus(
        chatRoomId: chatRoomId,
        userId: userId,
      );

  /// [ReadStatus] を作成する.
  Future<void> createReadStatus({
    required String chatRoomId,
    required String userId,
  }) =>
      _readStatusRepository.setLastReadAt(
        chatRoomId: chatRoomId,
        userId: userId,
      );
}

既読表示機能のために相手が最後にチャットを読んだ時間を持ってくるreadStatusServiceProviderを作りましたが、読み取れてなくてその原因がわからず相談したいです。。。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
1. 機能開発 機能開発
Projects
None yet
Development

No branches or pull requests

3 participants