Чтобы создать приложение для чата 1–1 во Flutter с помощью Cloud Firestore, вы можете выполнить следующие действия:

  1. Создайте новый проект Flutter в предпочитаемой вами среде разработки.
  2. Настройте проект Firebase и подключите его к приложению Flutter, следуя инструкциям в Документации Firebase.
  3. В консоли Firebase создайте новую базу данных Cloud Firestore и установите для нее правила безопасности, чтобы разрешить доступ для чтения и записи для пользователей, прошедших проверку подлинности.
  4. В своем приложении Flutter установите пакет cloud_firestore.
  5. Реализуйте поток аутентификации в своем приложении с помощью службы аутентификации Firebase. Вы можете использовать адрес электронной почты/пароль, номер телефона или любой другой поддерживаемый поставщик удостоверений.
  6. Создайте экран чата в своем приложении, где пользователи могут отправлять и получать сообщения. Вы можете использовать виджет ListView для отображения сообщений в прокручиваемом списке.
  7. Используйте метод Cloud Firestore add() для сохранения сообщений в базе данных. Вы можете хранить каждое сообщение как документ в коллекции с полями для отправителя, получателя, текста сообщения и метки времени.
  8. Используйте прослушиватель Cloud Firestore snapshot для прослушивания обновлений коллекции сообщений в режиме реального времени и обновления экрана чата при получении новых сообщений.

Это общий обзор того, как вы можете создать приложение для чата 1-1 во Flutter с помощью Cloud Firestore. Дайте мне знать, если у вас есть какие-либо вопросы или вам нужна дополнительная информация.

Это пример исходного кода для этого приложения:

import 'dart:math';

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(const MyApp());
}

int user = Random().nextInt(3000);

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(primaryColor: Colors.teal),
      title: 'Chat App',
      home: const ChatScreen(),
    );
  }
}

Экран чата. дротик

class ChatScreen extends StatefulWidget {
  const ChatScreen({Key? key}) : super(key: key);

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


class _ChatScreenState extends State<ChatScreen> {
  final _firestore = FirebaseFirestore.instance;
  final _textController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Row(
          children: const [
            CircleAvatar(
              radius: 22,
              backgroundImage: NetworkImage(
                'https://user-images.githubusercontent.com/89972827/208123817-524df66c-fcc6-4a29-8c27-cdeb3c989e41.png',
              ),
            ),
            SizedBox(
              width: 10,
            ),
            Text('Chat'),
          ],
        ),
        actions: [
          IconButton(
            onPressed: () {},
            icon: const Icon(Icons.videocam),
          ),
          IconButton(
            onPressed: () {},
            icon: const Icon(Icons.phone),
          ),
          IconButton(
            onPressed: () {},
            icon: const Icon(Icons.more_vert),
          ),
        ],
        backgroundColor: Colors.grey.shade800,
      ),
      backgroundColor: Colors.grey.shade800,
      body: Column(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          const MessageStream(),
          Container(
            padding: const EdgeInsets.all(5),
            child: Row(
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                Expanded(
                  child: Container(
                    decoration: BoxDecoration(
                      borderRadius: const BorderRadius.all(Radius.circular(50)),
                      color: Colors.grey.shade700,
                    ),
                    child: TextField(
                      controller: _textController,
                      cursorColor: Colors.teal,
                      style: const TextStyle(color: Colors.white),
                      decoration: const InputDecoration(
                        contentPadding: EdgeInsets.symmetric(
                          vertical: 10.0,
                          horizontal: 20.0,
                        ),
                        hintText: 'Message',
                        hintStyle: TextStyle(color: Colors.white),
                        border: InputBorder.none,
                      ),
                    ),
                  ),
                ),
                ElevatedButton(
                  onPressed: () async {
                    if (_textController.text.trim() != '') {
                      await _firestore.collection('messages').add({
                        'text': _textController.text,
                        'sender': '$user',
                        'dt': DateTime.now(),
                      });
                      _textController.clear();
                    }
                  },
                  style: ElevatedButton.styleFrom(
                    minimumSize: const Size(45, 45),
                    shape: const CircleBorder(),
                    primary: Colors.teal,
                  ),
                  child: const Icon(
                    Icons.send,
                    size: 25,
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

Поток сообщений

class MessageStream extends StatelessWidget {
  const MessageStream({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<QuerySnapshot>(
      stream: FirebaseFirestore.instance
          .collection('messages')
          .orderBy(
            'dt',
            descending: true,
          )
          .snapshots(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          return const Center(
            child: CircularProgressIndicator(
              backgroundColor: Colors.teal,
            ),
          );
        }
        final messages = snapshot.data!.docs;
        List<MessageBubble> messageBubbles = [];
        for (var message in messages) {
          final messageText = (message.data()! as Map)['text'];
          final messageSender = (message.data()! as Map)['sender'];
          String currentUser = user.toString();
          final messageBubble = MessageBubble(
            sender: messageSender,
            text: messageText,
            isMe: currentUser == messageSender,
          );
          messageBubbles.add(messageBubble);
        }
        return Expanded(
          child: ListView(
            reverse: true,
            padding:
                const EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
            children: messageBubbles,
          ),
        );
      },
    );
  }
}

Пузырь сообщений

class MessageBubble extends StatelessWidget {
  const MessageBubble({
    Key? key,
    required this.sender,
    required this.text,
    required this.isMe,
  }) : super(key: key);

  final String sender;
  final String text;
  final bool isMe;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(10.0),
      child: Column(
        crossAxisAlignment:
            isMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
        children: [
          Material(
            borderRadius: isMe
                ? const BorderRadius.only(
                    topLeft: Radius.circular(30.0),
                    bottomLeft: Radius.circular(30.0),
                    bottomRight: Radius.circular(30.0),
                  )
                : const BorderRadius.only(
                    topRight: Radius.circular(30.0),
                    bottomLeft: Radius.circular(30.0),
                    bottomRight: Radius.circular(30.0),
                  ),
            color: isMe ? Colors.teal : Colors.grey.shade700,
            child: Padding(
              padding:
                  const EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    sender,
                    style: TextStyle(
                      fontSize: 12.0,
                      fontWeight: FontWeight.bold,
                      color: Colors
                          .primaries[Random().nextInt(Colors.primaries.length)],
                    ),
                  ),
                  const SizedBox(
                    height: 5,
                  ),
                  Text(
                    text,
                    style: TextStyle(
                      color: isMe ? Colors.white : Colors.white,
                      fontSize: 15.0,
                    ),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

Спасибо Оставьте хлопок и комментарий, если вам понравилась эта статья.