Firebase for Flutter'ı tanıyın

Koleksiyonlar ile düzeninizi koruyun İçeriği tercihlerinize göre kaydedin ve kategorilere ayırın.

1. Başlamadan önce

Bu codelab'de, Android ve iOS için Flutter mobil uygulamaları oluşturmak için Firebase'in bazı temellerini öğreneceksiniz.

Önkoşullar

Bu codelab, Flutter'a aşina olduğunuzu ve Flutter SDK'yı ve bir düzenleyiciyi yüklediğinizi varsayar.

ne yaratacaksın

Bu kod laboratuvarında, Flutter kullanarak Android, iOS, Web ve macOS üzerinde bir etkinlik LCV ve ziyaretçi defteri sohbet uygulaması oluşturacaksınız. Firebase Authentication ile kullanıcıların kimliğini doğrulayacak ve Cloud Firestore'u kullanarak verileri senkronize edeceksiniz.

Neye ihtiyacın olacak

Bu codelab'i aşağıdaki cihazlardan herhangi birini kullanarak çalıştırabilirsiniz:

Yukarıdakilere ek olarak, şunlara da ihtiyacınız olacak:

  • Chrome gibi seçtiğiniz bir tarayıcı.
  • Dart ve Flutter eklentileriyle yapılandırılmış Android Studio veya VS Code gibi seçtiğiniz bir IDE veya metin düzenleyici.
  • Flutter'ın en son stable sürümü (ya da uçlarda yaşamayı seviyorsanız beta ).
  • Firebase projenizi oluşturmak ve yönetmek için gmail hesabı gibi bir Google hesabı.
  • firebase komut satırı aracı , gmail hesabınıza giriş yaptı.
  • Codelab'ın örnek kodu. Kodun nasıl alınacağını öğrenmek için sonraki adıma bakın.

2. Örnek kodu alın

Projemizin ilk sürümünü GitHub'dan indirerek başlayalım.

GitHub deposunu komut satırından klonlayın:

git clone https://github.com/flutter/codelabs.git flutter-codelabs

Alternatif olarak, GitHub'ın cli aracını yüklediyseniz:

gh repo clone flutter/codelabs flutter-codelabs

Örnek kod, bir codelab koleksiyonunun kodunu içeren flutter-codelabs dizinine klonlanmalıdır. Bu codelab'in kodu flutter-codelabs/firebase-get-to-know-flutter .

flutter-codelabs/firebase-get-to-know-flutter altındaki dizin yapısı, adlandırılmış her adımın sonunda nerede olmanız gerektiğini gösteren bir dizi anlık görüntüdür. Bu 2. Adımdır, bu nedenle eşleşen dosyaları bulmak şu kadar kolaydır:

cd flutter-codelabs/firebase-get-to-know-flutter/step_02

İleri atlamak veya bir adımdan sonra bir şeyin nasıl görünmesi gerektiğini görmek istiyorsanız, ilgilendiğiniz adımın adını taşıyan dizine bakın.

Başlangıç ​​uygulamasını içe aktarın

flutter-codelabs/firebase-get-to-know-flutter/step_02 dizinini tercih ettiğiniz IDE'ye açın veya içe aktarın. Bu dizin, henüz işlevsel olmayan bir Flutter buluşma uygulamasından oluşan kod laboratuvarı için başlangıç ​​kodunu içerir.

Üzerinde çalışılacak dosyaları bulun

Bu uygulamadaki kod, birden çok dizine yayılmıştır. Bu işlevsellik ayrımı, kodu işlevselliğe göre gruplayarak üzerinde çalışmayı kolaylaştırmak için tasarlanmıştır.

Projede aşağıdaki dosyaları bulun:

  • lib/main.dart : Bu dosya, ana giriş noktasını ve uygulama pencere öğesini içerir.
  • lib/src/widgets.dart : Bu dosya, uygulamanın stilini standartlaştırmaya yardımcı olacak bir avuç widget içerir. Bunlar, başlangıç ​​uygulamasının ekranını oluşturmak için kullanılır.
  • lib/src/authentication.dart : Bu dosya, Firebase e-posta tabanlı kimlik doğrulaması için bir oturum açma kullanıcı deneyimi oluşturmak için bir dizi widget ile kısmen FirebaseUI Auth uygulamasını içerir. Yetkilendirme akışına yönelik bu widget'lar henüz başlangıç ​​uygulamasında kullanılmamaktadır, ancak bunları yakında bağlayacaksınız.

Uygulamanın geri kalanını oluşturmak için gereken ek dosyaları ekleyeceksiniz.

lib/main.dart dosyasını gözden geçirme

Bu uygulama, Roboto'yu tüm uygulama boyunca varsayılan yazı tipi yapmamızı sağlamak için google_fonts paketinden yararlanır. Motive okuyucu için bir alıştırma, fonts.google.com'u keşfetmek ve orada keşfettiğiniz yazı tiplerini uygulamanın farklı bölümlerinde kullanmaktır.

lib/src/widgets.dart adresindeki yardımcı pencere öğelerini Header , Paragraph ve IconAndDetail . Bu widget'lar, yinelenen kodu ortadan kaldırarak HomePage açıklanan sayfa düzenindeki dağınıklığı azaltır. Bu, tutarlı bir görünüm ve his sağlamanın ek avantajına sahiptir.

Uygulamanız Android, iOS, Web ve macOS'ta şöyle görünür:

Uygulama önizlemesi

3. Bir Firebase projesi oluşturun ve kurun

Etkinlik bilgilerini görüntülemek konuklarınız için harikadır, ancak yalnızca etkinlikleri göstermek hiç kimse için pek yararlı değildir. Bu uygulamaya bazı dinamik işlevler ekleyelim. Bunun için Firebase'i uygulamanıza bağlamanız gerekir. Firebase'i kullanmaya başlamak için bir Firebase projesi oluşturmanız ve ayarlamanız gerekir.

Firebase projesi oluşturun

  1. Firebase'de oturum açın.
  2. Firebase konsolunda, Proje Ekle'yi (veya Bir proje oluşturun ) tıklayın ve Firebase projenizi Firebase-Flutter-Codelab olarak adlandırın .

4395e4e67c08043a.png

  1. Proje oluşturma seçeneklerine tıklayın. İstenirse Firebase şartlarını kabul edin. Bu uygulama için Analytics kullanmayacağınız için Google Analytics kurulumunu atlayın.

b7138cde5f2c7b61.png

Firebase projeleri hakkında daha fazla bilgi edinmek için Firebase projelerini anlama bölümüne bakın.

Oluşturduğunuz uygulama, web uygulamaları için kullanılabilen birkaç Firebase ürünü kullanıyor:

  • Kullanıcılarınızın uygulamanızda oturum açmasına izin vermek için Firebase Kimlik Doğrulaması .
  • Bulutta yapılandırılmış verileri kaydetmek ve veriler değiştiğinde anında bildirim almak için Cloud Firestore .
  • Veritabanınızın güvenliğini sağlamak için Firebase Güvenlik Kuralları .

Bu ürünlerden bazıları özel yapılandırmaya ihtiyaç duyar veya Firebase konsolu kullanılarak etkinleştirilmesi gerekir.

Firebase Kimlik Doğrulaması için e-posta ile oturum açmayı etkinleştirin

Kullanıcıların web uygulamasında oturum açmasına izin vermek için bu codelab için E-posta/Parola ile oturum açma yöntemini kullanacaksınız:

  1. Firebase konsolunda, sol paneldeki Oluştur menüsünü genişletin.
  2. Kimlik Doğrulama'yı ve ardından Başlarken düğmesini, ardından Oturum açma yöntemi sekmesini (veya doğrudan Oturum açma yöntemi sekmesine gitmek için burayı tıklayın ) tıklayın.
  3. Oturum açma sağlayıcıları listesinde E-posta/Parola'ya tıklayın, Etkinleştir anahtarını açık konuma ayarlayın ve ardından Kaydet'e tıklayın . 58e3e3e23c2f16a4.png

Cloud Firestore'u Etkinleştir

Web uygulaması, sohbet mesajlarını kaydetmek ve yeni sohbet mesajları almak için Cloud Firestore'u kullanır.

Cloud Firestore'u etkinleştirin:

  1. Firebase konsolunun Oluştur bölümünde, Cloud Firestore öğesini tıklayın.
  2. Veritabanı oluştur 'u tıklayın. 99e8429832d23fa3.png
  1. Test modunda başlat seçeneğini seçin. Güvenlik kurallarıyla ilgili yasal uyarıyı okuyun. Test modu, geliştirme sırasında veritabanına özgürce yazabilmenizi sağlar. İleri'yi tıklayın. 6be00e26c72ea032.png
  1. Veritabanınız için konumu seçin (Yalnızca varsayılanı kullanabilirsiniz). Bu konumun daha sonra değiştirilemeyeceğini unutmayın. 278656eefcfb0216.png
  2. Etkinleştir'i tıklayın.

4. Firebase yapılandırması

Firebase'i Flutter ile kullanmak için Flutter projesini FlutterFire kitaplıklarını doğru kullanacak şekilde yapılandırmak için bir süreci izlemeniz gerekir:

  • Projenize FlutterFire bağımlılıklarını ekleyin
  • İstediğiniz platformu Firebase projesine kaydedin
  • Platforma özel yapılandırma dosyasını indirin ve koda ekleyin.

Flutter uygulamanızın üst düzey dizininde android , ios , macos ve web adlı alt dizinler vardır. Bu dizinler, sırasıyla iOS ve Android için platforma özgü yapılandırma dosyalarını tutar.

Bağımlılıkları yapılandır

Bu uygulamada kullandığınız iki Firebase ürünü için FlutterFire kitaplıklarını eklemeniz gerekir - Firebase Auth ve Cloud Firestore. Bağımlılıkları eklemek için aşağıdaki üç komutu çalıştırın.

$ flutter pub add firebase_core

firebase_core , tüm Firebase Flutter eklentileri için gereken ortak koddur.

$ flutter pub add firebase_auth

firebase_auth , Firebase'in Kimlik Doğrulama özelliğiyle entegrasyon sağlar.

$ flutter pub add cloud_firestore

cloud_firestore , Cloud Firestore veri deposuna erişim sağlar.

$ flutter pub add provider

firebase_ui_auth paketi, özellikle kimlik doğrulama akışlarıyla geliştirici hızını artırmak için bir dizi widget ve yardımcı program sağlar.

$ flutter pub add firebase_ui_auth

Gerekli paketleri eklerken, Firebase'i uygun şekilde kullanmak için iOS, Android, macOS ve Web runner projelerini de yapılandırmanız gerekir. İş mantığının görüntü mantığından ayrılmasını sağlayacak provider paketini de kullanıyorsunuz.

flutterfire yükleme

FlutterFire CLI, temeldeki Firebase CLI'ye bağlıdır. Henüz yapmadıysanız, makinenizde Firebase CLI'nin kurulu olduğundan emin olun.

Ardından, aşağıdaki komutu çalıştırarak FlutterFire CLI'yi kurun:

$ dart pub global activate flutterfire_cli

Yüklendikten sonra, flutterfire komutu küresel olarak kullanılabilir olacaktır.

Uygulamalarınızı yapılandırma

CLI, belirli bir platform için tüm yapılandırmayı oluşturmak üzere Firebase projenizden ve seçilen proje uygulamalarından bilgi alır.

Uygulamanızın kökünde, configure komutunu çalıştırın:

$ flutterfire configure

Konfigürasyon komutu bir dizi işlemde size rehberlik edecektir:

  1. Bir Firebase projesi seçme (.firebaserc dosyasına göre veya Firebase Konsolundan).
  2. Hangi platformlar için (ör. Android, iOS, macOS ve web) yapılandırmak istediğinizi belirtin.
  3. Yapılandırmayı çıkarmak için seçilen platformlar için hangi Firebase uygulamalarının kullanılması gerektiğini belirleyin. Varsayılan olarak, CLI, mevcut proje yapılandırmanıza göre Firebase uygulamalarını otomatik olarak eşleştirmeye çalışır.
  4. Projenizde bir firebase_options.dart dosyası oluşturun.

macOS'u yapılandırın

MacOS'ta Flutter, tamamen korumalı uygulamalar oluşturur. Bu uygulama, Firebase sunucularıyla iletişim kurmak için ağı kullanarak entegre olduğundan, uygulamanızı ağ istemcisi ayrıcalıklarıyla yapılandırmanız gerekecektir.

macos/Runner/DebugProfile.yetkilendirmeleri

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>com.apple.security.app-sandbox</key>
	<true/>
	<key>com.apple.security.cs.allow-jit</key>
	<true/>
	<key>com.apple.security.network.server</key>
	<true/>
  <!-- Add the following two lines -->
	<key>com.apple.security.network.client</key>
	<true/>
</dict>
</plist>

macos/Runner/Release.yetkilendirmeleri

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>com.apple.security.app-sandbox</key>
	<true/>
  <!-- Add the following two lines -->
	<key>com.apple.security.network.client</key>
	<true/>
</dict>
</plist>

Daha fazla ayrıntı için Yetkiler ve Uygulama Korumalı Alanı'na bakın.

5. Kullanıcı oturum açma (RSVP) ekleyin

Firebase'i uygulamaya eklediğinize göre, kişileri Firebase Authentication kullanarak kaydeden bir LCV düğmesi ayarlayabilirsiniz. Android yerel, iOS yerel ve Web için önceden oluşturulmuş FirebaseUI Auth paketleri vardır, ancak Flutter için bu özelliği oluşturmanız gerekir.

Adım 2'de aldığınız proje, kimlik doğrulama akışının çoğu için kullanıcı arabirimini uygulayan bir dizi pencere öğesi içeriyordu. Firebase Authentication'ı uygulamaya entegre etmek için iş mantığını uygulayacaksınız.

Sağlayıcı ile İş Mantığı

provider paketini, uygulamanın Flutter widget'ları ağacı boyunca merkezileştirilmiş bir uygulama durumu nesnesini kullanılabilir hale getirmek için kullanacaksınız. Başlangıç ​​olarak, lib/main.dart üst kısmındaki içe aktarmaları değiştirin:

lib/main.dart

import 'dart:async';                                     // new
import 'package:firebase_auth/firebase_auth.dart'        // new
    hide EmailAuthProvider, PhoneAuthProvider;           // new
import 'package:firebase_core/firebase_core.dart';       // new
import 'package:firebase_ui_auth/firebase_ui_auth.dart'; // new
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';                 // new

import 'firebase_options.dart';                          // new
import 'src/authentication.dart';                        // new
import 'src/widgets.dart';

import satırları, Firebase Core ve Auth'u tanıtır, uygulama durumu nesnesini pencere öğesi ağacı aracılığıyla kullanılabilir hale getirmek için kullandığınız provider paketini çeker ve firebase_ui_auth kimlik doğrulama pencere öğelerini içerir.

Bu uygulama durumu nesnesi ApplicationState , bu adım için bir ana sorumluluğu vardır; bu, pencere öğesi ağacını kimliği doğrulanmış bir duruma yönelik bir güncelleme olduğu konusunda uyarmaktır. lib/main.dart sonuna aşağıdaki sınıfı ekleyin:

lib/main.dart

class ApplicationState extends ChangeNotifier {
  ApplicationState() {
    init();
  }

  bool _loggedIn = false;
  bool get loggedIn => _loggedIn;

  Future<void> init() async {
    await Firebase.initializeApp(
        options: DefaultFirebaseOptions.currentPlatform);

    FirebaseUIAuth.configureProviders([
      EmailAuthProvider(),
    ]);

    FirebaseAuth.instance.userChanges().listen((user) {
      if (user != null) {
        _loggedIn = true;
      } else {
        _loggedIn = false;
      }
      notifyListeners();
    });
  }
}

Burada, bir kullanıcının oturum açma durumunu belirten uygulamaya iletişim kurmak için bir sağlayıcı kullanıyoruz, başka bir şey değil. Bir kullanıcıya giriş yapmak için, uygulamalarınız için giriş ekranlarını hızlı bir şekilde başlatmanın harika bir yolu olan firebase_ui_auth tarafından sağlanan UI'leri kullanacağız.

Kimlik Doğrulama akışını entegre etme

Artık uygulama durumunun başlangıcına sahip olduğunuza göre, uygulama durumunu uygulama başlatmaya bağlamanın ve kimlik doğrulama akışını HomePage Sayfaya eklemenin zamanı geldi. provider paketi aracılığıyla uygulama durumunu entegre etmek için ana giriş noktasını güncelleyin:

lib/main.dart

void main() {
  // Modify from here
  WidgetsFlutterBinding.ensureInitialized();

  runApp(ChangeNotifierProvider(
    create: (context) => ApplicationState(),
    builder: ((context, child) => const App()),
  ));
  // to here.
}

main işlevde yapılan değişiklik, sağlayıcı paketini ChangeNotifierProvider pencere aracını kullanarak uygulama durumu nesnesini başlatmaktan sorumlu kılar. Uygulama durumu nesnesi ChangeNotifier genişlettiği ve bu, provider paketinin bağımlı pencere öğelerinin ne zaman yeniden görüntüleneceğini bilmesini sağladığı için bu belirli sağlayıcı sınıfını kullanıyorsunuz.

Flutter için FirebaseUI kullandığımızdan, uygulamamızı FirebaseUI'nin bize sağladığı farklı ekranlarda gezinmeyi işleyecek şekilde güncelleyeceğiz. Bunu yapmak için bir initialRoute özelliği ekliyoruz ve routes özelliğinin altına yönlendirme yapabileceğimiz tercih edilen ekranlarımızı ekliyoruz. Değişiklikler şöyle görünmelidir:

lib/main.dart

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      //Start adding here
      initialRoute: '/home',
      routes: {
        '/home': (context) {
          return const HomePage();
        },
        '/sign-in': ((context) {
          return SignInScreen(
            actions: [
              ForgotPasswordAction(((context, email) {
                Navigator.of(context)
                    .pushNamed('/forgot-password', arguments: {'email': email});
              })),
              AuthStateChangeAction(((context, state) {
                if (state is SignedIn || state is UserCreated) {
                  var user = (state is SignedIn)
                      ? state.user
                      : (state as UserCreated).credential.user;
                  if (user == null) {
                    return;
                  }
                  if (state is UserCreated) {
                    user.updateDisplayName(user.email!.split('@')[0]);
                  }
                  if (!user.emailVerified) {
                    user.sendEmailVerification();
                    const snackBar = SnackBar(
                        content: Text(
                            'Please check your email to verify your email address'));
                    ScaffoldMessenger.of(context).showSnackBar(snackBar);
                  }
                  Navigator.of(context).pushReplacementNamed('/home');
                }
              })),
            ],
          );
        }),
        '/forgot-password': ((context) {
          final arguments = ModalRoute.of(context)?.settings.arguments
              as Map<String, dynamic>?;

          return ForgotPasswordScreen(
            email: arguments?['email'] as String,
            headerMaxExtent: 200,
          );
        }),
        '/profile': ((context) {
          return ProfileScreen(
            providers: [],
            actions: [
              SignedOutAction(
                ((context) {
                  Navigator.of(context).pushReplacementNamed('/home');
                }),
              ),
            ],
          );
        })
      },
      // end adding here
      title: 'Firebase Meetup',
      theme: ThemeData(
        buttonTheme: Theme.of(context).buttonTheme.copyWith(
              highlightColor: Colors.deepPurple,
            ),
        primarySwatch: Colors.deepPurple,
        textTheme: GoogleFonts.robotoTextTheme(
          Theme.of(context).textTheme,
        ),
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
    );
  }
}

Her ekran, kimlik doğrulama akışının yeni durumuna bağlı olarak, kendisiyle ilişkilendirilmiş farklı bir eylem türüne sahiptir. Kimlik doğrulamadaki çoğu durum değişikliğinden sonra, ister ana ekran isterse profil gibi farklı bir ekran olsun, tercih edilen bir ekrana geri dönebiliriz. Son olarak, HomePage derleme yöntemini güncelleyerek uygulama durumunu AuthFunc ile entegre edin:

lib/main.dart

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Consumer<ApplicationState>(
        builder: (context, appState, child) => Scaffold(
              appBar: AppBar(
                title: const Text('Firebase Meetup'),
              ),
              body: ListView(
                children: <Widget>[
                  Image.asset('assets/codelab.png'),
                  const SizedBox(height: 8),
                  const IconAndDetail(Icons.calendar_today, 'October 30'),
                  const IconAndDetail(Icons.location_city, 'San Francisco'),
                  // Add from here
                  Consumer<ApplicationState>(
                    builder: (context, appState, _) => AuthFunc(
                        loggedIn: appState.loggedIn,
                        signOut: () {
                          FirebaseAuth.instance.signOut();
                        }),
                  ),
                  // to here
                  const Divider(
                    height: 8,
                    thickness: 1,
                    indent: 8,
                    endIndent: 8,
                    color: Colors.grey,
                  ),
                  const Header("What we'll be doing"),
                  const Paragraph(
                    'Join us for a day full of Firebase Workshops and Pizza!',
                  ),
                ],
              ),
            ));
  }
}

AuthFunc pencere aracını başlatır ve bir Consumer pencere aracına sararsınız. Tüketici pencere öğesi, uygulama durumu değiştiğinde, provider paketinin ağacın bir bölümünü yeniden oluşturmak için kullanılabileceği olağan yoldur. AuthFunc parçacığı, şimdi test edeceğiniz ek araçlardır.

Kimlik Doğrulama akışını test etme

cdf2d25e436bd48d.png

Kullanıcının SignInScreen başlatmak için LCV düğmesine dokunabileceği kimlik doğrulama akışının başlangıcı buradadır.

2a2cd6d69d172369.png

E-postayı girdikten sonra, sistem kullanıcının kayıtlı olup olmadığını onaylar, bu durumda kullanıcıdan bir şifre istenir, alternatif olarak kullanıcı kayıtlı değilse, kayıt formuna geçer.

e5e65065dba36b54.png

Hata işleme akışını kontrol etmek için kısa bir parola (altı karakterden az) girmeyi denediğinizden emin olun. Kullanıcı kayıtlıysa, bunun yerine şifreyi görecektir.

Bu sayfada, bu sayfadaki hata işlemeyi kontrol etmek için yanlış şifreler girdiğinizden emin olun. Son olarak, kullanıcı oturum açtıktan sonra, kullanıcıya tekrar oturumu kapatma olanağı sunan oturum açma deneyimini göreceksiniz.

4ed811a25b0cf816.png

Ve bununla bir kimlik doğrulama akışı uyguladınız. Tebrikler!

6. Cloud Firestore'a mesaj yazın

Kullanıcıların geldiğini bilmek harika, ancak konuklara uygulamada yapacakları başka bir şey verelim. Ya bir ziyaretçi defterine mesaj bırakabilirlerse? Gelmek için neden heyecanlı olduklarını veya kiminle tanışmayı umduklarını paylaşabilirler.

Kullanıcıların uygulamada yazdığı sohbet mesajlarını saklamak için Cloud Firestore'u kullanacaksınız.

Veri örneği

Cloud Firestore bir NoSQL veritabanıdır ve veritabanında depolanan veriler koleksiyonlara, belgelere, alanlara ve alt koleksiyonlara bölünür. Sohbetin her mesajını, guestbook adı verilen üst düzey bir koleksiyonda bir belge olarak depolayacaksınız.

7c20dc8424bb1d84.png

Firestore'a mesaj ekleyin

Bu bölümde, kullanıcıların veritabanına yeni mesajlar yazması için işlevsellik ekleyeceksiniz. İlk olarak, UI öğelerini (form alanı ve gönder düğmesi) eklersiniz ve ardından bu öğeleri veritabanına bağlayan kodu eklersiniz.

İlk olarak, cloud_firestore paketi ve dart:async için içe aktarmaları ekleyin.

lib/main.dart

import 'dart:async';                                    // new

import 'package:cloud_firestore/cloud_firestore.dart';  // new
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';

import 'firebase_options.dart';
import 'src/authentication.dart';
import 'src/widgets.dart';

Bir mesaj alanının ve bir gönder düğmesinin UI öğelerini oluşturmak için, lib/main.dart GuestBook yeni bir durum bilgisi olan Konuk Defteri'ni ekleyin.

lib/main.dart

class GuestBook extends StatefulWidget {
  const GuestBook({required this.addMessage, super.key});
  final FutureOr<void> Function(String message) addMessage;

  @override
  State<GuestBook> createState() => _GuestBookState();
}

class _GuestBookState extends State<GuestBook> {
  final _formKey = GlobalKey<FormState>(debugLabel: '_GuestBookState');
  final _controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Form(
        key: _formKey,
        child: Row(
          children: [
            Expanded(
              child: TextFormField(
                controller: _controller,
                decoration: const InputDecoration(
                  hintText: 'Leave a message',
                ),
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Enter your message to continue';
                  }
                  return null;
                },
              ),
            ),
            const SizedBox(width: 8),
            StyledButton(
              onPressed: () async {
                if (_formKey.currentState!.validate()) {
                  await widget.addMessage(_controller.text);
                  _controller.clear();
                }
              },
              child: Row(
                children: const [
                  Icon(Icons.send),
                  SizedBox(width: 4),
                  Text('SEND'),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Burada bir iki ilgi çekici nokta var. İlk olarak, bir Form başlatıyorsunuz, böylece mesajın gerçekten bir içeriği olduğunu doğrulayabilirsiniz ve eğer yoksa kullanıcıya bir hata mesajı gösterebilirsiniz. Bir formu doğrulamanın yolu, formun arkasındaki form durumuna erişmeyi içerir ve bunun için bir GlobalKey . Tuşlar ve bunların nasıl kullanılacağı hakkında daha fazla bilgi için lütfen Flutter Widgets 101 bölümü "Anahtarlar Ne Zaman Kullanılır" bölümüne bakın.

Ayrıca, pencere öğelerinin düzenlenme biçimine de dikkat edin, bir TextFormField ve kendisi bir Row içeren bir StyledButton içeren bir Row var. Ayrıca TextFormField öğesinin bir Expanded pencere aracına sarıldığını unutmayın; bu, TextFormField satırda fazladan yer kaplamaya zorlar. Bunun neden gerekli olduğunu daha iyi anlamak için lütfen Kısıtlamaları anlama bölümünü okuyun.

Artık kullanıcının Ziyaretçi Defterine eklemek üzere bir metin girmesini sağlayan bir widget'ınız olduğuna göre, onu ekrana getirmeniz gerekir. Bunu yapmak için, ListView 'ın alt öğelerinin altına aşağıdaki iki satırı eklemek için HomePage gövdesini düzenleyin:

const Header("What we'll be doing"),
const Paragraph(
  'Join us for a day full of Firebase Workshops and Pizza!',
),
// Add the following two lines.
const Header('Discussion'),
GuestBook(addMessage: (message) => print(message)),

Bu, Widget'ı görüntülemek için yeterli olsa da, yararlı bir şey yapmak için yeterli değildir. Bu kodu, işlevsel hale getirmek için kısa süre içinde güncelleyeceksiniz.

Uygulama önizlemesi

GÖNDER düğmesini tıklayan bir kullanıcı aşağıdaki kod parçacığını tetikleyecektir. Mesaj giriş alanının içeriğini veritabanının guestbook koleksiyonuna ekler. Özellikle, addMessageToGuestBook yöntemi, mesaj içeriğini yeni bir belgeye (otomatik olarak oluşturulan bir kimlikle) guestbook koleksiyonuna ekler.

FirebaseAuth.instance.currentUser.uid öğesinin, Firebase Authentication'ın oturum açmış tüm kullanıcılar için verdiği otomatik olarak oluşturulan benzersiz kimliğin bir referansı olduğunu unutmayın.

lib/main.dart dosyasında başka bir değişiklik yapın. addMessageToGuestBook yöntemini ekleyin. Bir sonraki adımda kullanıcı arayüzünü ve bu yeteneği birbirine bağlayacaksınız.

lib/main.dart

class ApplicationState extends ChangeNotifier {

  // Current content of ApplicationState elided ...

  // Add from here
  Future<DocumentReference> addMessageToGuestBook(String message) {
    if (!_loggedIn) {
      throw Exception('Must be logged in');
    }

    return FirebaseFirestore.instance
        .collection('guestbook')
        .add(<String, dynamic>{
      'text': message,
      'timestamp': DateTime.now().millisecondsSinceEpoch,
      'name': FirebaseAuth.instance.currentUser!.displayName,
      'userId': FirebaseAuth.instance.currentUser!.uid,
    });
  }
  // To here
}

UI'yi veritabanına bağlama

Kullanıcının Ziyaretçi Defterine eklemek istediği metni girebileceği bir kullanıcı arayüzünüz var ve girişi Cloud Firestore'a eklemek için kodunuz var. Şimdi yapmanız gereken tek şey ikisini birbirine bağlamak. lib/main.dart HomePage widget'ında aşağıdaki değişikliği yapın.

lib/main.dart

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Firebase Meetup'),
      ),
      body: ListView(
        children: <Widget>[
          Image.asset('assets/codelab.png'),
          const SizedBox(height: 8),
          const IconAndDetail(Icons.calendar_today, 'October 30'),
          const IconAndDetail(Icons.location_city, 'San Francisco'),
          Consumer<ApplicationState>(
            builder: (context, appState, _) => AuthFunc(
                loggedIn: appState.loggedIn,
                signOut: () {
                  FirebaseAuth.instance.signOut();
                }),
          ),
          const Divider(
            height: 8,
            thickness: 1,
            indent: 8,
            endIndent: 8,
            color: Colors.grey,
          ),
          const Header("What we'll be doing"),
          const Paragraph(
            'Join us for a day full of Firebase Workshops and Pizza!',
          ),
          // Modify from here
          Consumer<ApplicationState>(
            builder: (context, appState, _) => Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                if (appState.loggedIn) ...[
                  const Header('Discussion'),
                  GuestBook(
                    addMessage: (message) =>
                        appState.addMessageToGuestBook(message),
                  ),
                ],
              ],
            ),
          ),
          // To here.
        ],
      ),
    );
  }
}

Bu adımın başında eklediğiniz iki satırı tam uygulama ile değiştirdiniz. Uygulama durumunu, oluşturmakta olduğunuz ağacın parçası için kullanılabilir hale getirmek için tekrar Consumer<ApplicationState> kullanıyorsunuz. Bu, kullanıcı arayüzüne mesaj giren birine tepki vermenizi ve bunu veritabanında yayınlamanızı sağlar. Bir sonraki bölümde, eklenen mesajların veritabanında yayınlanıp yayınlanmadığını test edeceksiniz.

Mesaj göndermeyi test et

  1. Uygulamada oturum açtığınızdan emin olun.
  2. "Merhaba!" gibi bir mesaj girin ve ardından GÖNDER 'i tıklayın.

Bu eylem, mesajı Cloud Firestore veritabanınıza yazar. Ancak, yine de verileri almayı uygulamanız gerektiğinden, mesajı gerçek Flutter uygulamanızda görmeyeceksiniz. Bunu bir sonraki adımda yapacaksınız.

Ancak yeni eklenen mesajı Firebase konsolunda görebilirsiniz.

Firebase konsolunda, Veritabanı panosunda , yeni eklediğiniz mesajınızla birlikte guestbook koleksiyonunu görmelisiniz. Mesaj göndermeye devam ederseniz, ziyaretçi defteri koleksiyonunuz aşağıdaki gibi birçok belge içerecektir:

Firebase konsolu

713870af0b3b63c.png

7. Mesajları okuyun

Konukların veritabanına mesaj yazabilmeleri çok güzel, ancak henüz uygulamada göremiyorlar. Bunu düzeltelim!

Mesajları senkronize et

Mesajları görüntülemek için, veriler değiştiğinde tetiklenen dinleyiciler eklemeniz ve ardından yeni mesajları gösteren bir UI öğesi oluşturmanız gerekir. Uygulamadan yeni eklenen mesajları dinleyen uygulama durumuna kod ekleyeceksiniz.

GuestBook widget'ının hemen üzerinde aşağıdaki değer sınıfı bulunur. Bu sınıf, Cloud Firestore'da depoladığınız verilerin yapılandırılmış bir görünümünü sunar.

lib/main.dart

class GuestBookMessage {
  GuestBookMessage({required this.name, required this.message});
  final String name;
  final String message;
}

ApplicationState durumu ve alıcıları tanımladığınız bölümüne aşağıdaki yeni satırları ekleyin:

lib/main.dart

  bool _loggedIn = false;
  bool get loggedIn => _loggedIn;

  // Add from here
  StreamSubscription<QuerySnapshot>? _guestBookSubscription;
  List<GuestBookMessage> _guestBookMessages = [];
  List<GuestBookMessage> get guestBookMessages => _guestBookMessages;
  // to here.

Ve son olarak, ApplicationState başlatma bölümünde, bir kullanıcı oturum açtığında belge koleksiyonu üzerinde bir sorguya abone olmak ve oturumu kapattığında abonelikten çıkmak için aşağıdakileri ekleyin.

lib/main.dart

  Future<void> init() async {
    await Firebase.initializeApp(
        options: DefaultFirebaseOptions.currentPlatform);

    FirebaseUIAuth.configureProviders([
      EmailAuthProvider(),
    ]);
    
    FirebaseAuth.instance.userChanges().listen((user) {
      if (user != null) {
        _loggedIn = true;
        _guestBookSubscription = FirebaseFirestore.instance
            .collection('guestbook')
            .orderBy('timestamp', descending: true)
            .snapshots()
            .listen((snapshot) {
          _guestBookMessages = [];
          for (final document in snapshot.docs) {
            _guestBookMessages.add(
              GuestBookMessage(
                name: document.data()['name'] as String,
                message: document.data()['text'] as String,
              ),
            );
          }
          notifyListeners();
        });
      } else {
        _loggedIn = false;
        _guestBookMessages = [];
        _guestBookSubscription?.cancel();
      }
      notifyListeners();
    });
  }

guestbook koleksiyonu üzerinde bir sorgu oluşturduğunuz ve bu koleksiyona abone olmayı ve abonelikten çıkmayı ele aldığınız yer olduğu için bu bölüm önemlidir. guestbook koleksiyonundaki mesajların yerel önbelleğini yeniden oluşturduğunuz akışı dinlersiniz ve ayrıca daha sonra aboneliğinizi iptal edebilmeniz için bu aboneliğe bir referans depolarsınız. Burada çok şey oluyor ve ne zaman daha net bir zihinsel model elde edileceğini incelemek için bir hata ayıklayıcıda biraz zaman harcamaya değer.

Daha fazla bilgi için Cloud Firestore belgelerine bakın.

GuestBook widget'ında, bu değişen durumu kullanıcı arayüzüne bağlamanız gerekir. Widget'ı, yapılandırmasının bir parçası olarak bir mesaj listesi ekleyerek değiştirirsiniz.

lib/main.dart

class GuestBook extends StatefulWidget {
  // Modify the following line
  const GuestBook({super.key, required this.addMessage, required this.messages,});
  final FutureOr<void> Function(String message) addMessage;
  final List<GuestBookMessage> messages; // new

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

Ardından, build yöntemini aşağıdaki gibi değiştirerek bu yeni konfigürasyonu _GuestBookState içinde ortaya çıkarıyoruz.

lib/main.dart

class _GuestBookState extends State<GuestBook> {
  final _formKey = GlobalKey<FormState>(debugLabel: '_GuestBookState');
  final _controller = TextEditingController();

  @override
  // Modify from here
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        // to here.
        Padding(
          padding: const EdgeInsets.all(8.0),
          child: Form(
            key: _formKey,
            child: Row(
              children: [
                Expanded(
                  child: TextFormField(
                    controller: _controller,
                    decoration: const InputDecoration(
                      hintText: 'Leave a message',
                    ),
                    validator: (value) {
                      if (value == null || value.isEmpty) {
                        return 'Enter your message to continue';
                      }
                      return null;
                    },
                  ),
                ),
                const SizedBox(width: 8),
                StyledButton(
                  onPressed: () async {
                    if (_formKey.currentState!.validate()) {
                      await widget.addMessage(_controller.text);
                      _controller.clear();
                    }
                  },
                  child: Row(
                    children: const [
                      Icon(Icons.send),
                      SizedBox(width: 4),
                      Text('SEND'),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
        // Modify from here
        const SizedBox(height: 8),
        for (var message in widget.messages)
          Paragraph('${message.name}: ${message.message}'),
        const SizedBox(height: 8),
      ],
      // to here.
    );
  }
}

Oluşturma yönteminin önceki içeriğini bir Column pencere aracıyla sararsınız ve ardından Sütun'un alt Column kuyruğuna, iletiler listesindeki her ileti için yeni bir Paragraph oluşturmak üzere bir koleksiyon eklersiniz.

Son olarak, şimdi yeni messages parametresiyle HomePage doğru bir şekilde oluşturmak için Ana GuestBook gövdesini güncellemeniz gerekiyor.

lib/main.dart

Consumer<ApplicationState>(
  builder: (context, appState, _) => Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      if (appState.loginState == ApplicationLoginState.loggedIn) ...[
        const Header('Discussion'),
        GuestBook(
          addMessage: (message) =>
              appState.addMessageToGuestBook(message),
          messages: appState.guestBookMessages, // new
        ),
      ],
    ],
  ),
),

Mesajları senkronize etmeyi test edin

Cloud Firestore, verileri veritabanına abone olan istemcilerle otomatik olarak ve anında senkronize eder.

  1. Veritabanında daha önce oluşturduğunuz mesajlar uygulamada görüntülenmelidir. Yeni mesajlar yazmaktan çekinmeyin; anında görünmelidirler.
  2. Çalışma alanınızı birden çok pencerede veya sekmede açarsanız, mesajlar sekmeler arasında gerçek zamanlı olarak eşitlenir.
  3. (İsteğe bağlı) Doğrudan Firebase konsolunun Veritabanı bölümünde manuel olarak silmeyi, değiştirmeyi veya yeni mesajlar eklemeyi deneyebilirsiniz; herhangi bir değişiklik kullanıcı arayüzünde görünmelidir.

Tebrikler! Uygulamanızda Cloud Firestore belgelerini okuyorsunuz!

Uygulama p incelemesi

8. Temel güvenlik kurallarını ayarlayın

Başlangıçta Cloud Firestore'u test modunu kullanacak şekilde ayarladınız; bu, veritabanınızın okuma ve yazma işlemlerine açık olduğu anlamına gelir. Ancak, test modunu yalnızca geliştirmenin çok erken aşamalarında kullanmalısınız. En iyi uygulama olarak, uygulamanızı geliştirirken veritabanınız için güvenlik kuralları oluşturmalısınız. Güvenlik, uygulamanızın yapısı ve davranışının ayrılmaz bir parçası olmalıdır.

Güvenlik Kuralları, veritabanınızdaki belgelere ve koleksiyonlara erişimi denetlemenize olanak tanır. Esnek kurallar sözdizimi, tüm veritabanına tüm yazmalardan belirli bir belgedeki işlemlere kadar her şeyle eşleşen kurallar oluşturmanıza olanak tanır.

Firebase konsolunda Cloud Firestore için güvenlik kuralları yazabilirsiniz:

  1. Firebase konsolunun Geliştirme bölümünde Veritabanı öğesine tıklayın ve ardından Kurallar sekmesini seçin (veya doğrudan Kurallar sekmesine gitmek için burayı tıklayın).
  2. Kuralların herkese açık olduğuna dair bir uyarı ile birlikte aşağıdaki varsayılan güvenlik kurallarını görmelisiniz.

7767a2d2e64e7275.png

Koleksiyonları tanımlayın

İlk olarak, uygulamanın veri yazdığı koleksiyonları tanımlayın.

match /databases/{database}/documents , güvenliğini sağlamak istediğiniz koleksiyonu tanımlayın:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /guestbook/{entry} {
     // You'll add rules here in the next step.
  }
}

Güvenlik kuralları ekle

Her ziyaretçi defteri belgesinde bir alan olarak Kimlik Doğrulama UID'sini kullandığınız için, Kimlik Doğrulama UID'sini alabilir ve belgeye yazmaya çalışan herkesin eşleşen bir Kimlik Doğrulama UID'si olduğunu doğrulayabilirsiniz.

Aşağıda gösterildiği gibi okuma ve yazma kurallarını kural kümenize ekleyin:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /guestbook/{entry} {
      allow read: if request.auth.uid != null;
      allow write:
        if request.auth.uid == request.resource.data.userId;
    }
  }
}

Şimdi, ziyaretçi defteri için, yalnızca oturum açmış kullanıcılar mesajları okuyabilir (herhangi bir mesaj!), ancak yalnızca bir mesajın yazarı bir mesajı düzenleyebilir.

Doğrulama kuralları ekle

Belgede beklenen tüm alanların mevcut olduğundan emin olmak için veri doğrulaması ekleyin:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /guestbook/{entry} {
      allow read: if request.auth.uid != null;
      allow write:
      if request.auth.uid == request.resource.data.userId
          && "name" in request.resource.data
          && "text" in request.resource.data
          && "timestamp" in request.resource.data;
    }
  }
}

9. Bonus adım: Öğrendiklerinizi uygulayın

Bir katılımcının LCV durumunu kaydedin

Şu anda uygulamanız, etkinlikle ilgilenen kişilerin sohbet etmeye başlamasına izin veriyor. Ayrıca, birinin gelip gelmediğini bilmenin tek yolu, onu sohbette yayınlamasıdır. Organize olalım ve kaç kişinin geleceğini insanlara bildirelim.

Uygulama durumuna birkaç yeni yetenek ekleyeceksiniz. Birincisi, oturum açmış bir kullanıcının katılıp katılmadıklarını aday gösterme yeteneğidir. İkinci yetenek, gerçekte kaç kişinin katıldığının bir sayacıdır.

lib/main.dart içinde, UI kodunun bu durumla etkileşime girmesini sağlamak için erişimciler bölümüne aşağıdakini ekleyin:

lib/main.dart

int _attendees = 0;
int get attendees => _attendees;

Attending _attending = Attending.unknown;
StreamSubscription<DocumentSnapshot>? _attendingSubscription;
Attending get attending => _attending;
set attending(Attending attending) {
  final userDoc = FirebaseFirestore.instance
      .collection('attendees')
      .doc(FirebaseAuth.instance.currentUser!.uid);
  if (attending == Attending.yes) {
    userDoc.set(<String, dynamic>{'attending': true});
  } else {
    userDoc.set(<String, dynamic>{'attending': false});
  }
}

ApplicationState init yöntemini aşağıdaki gibi güncelleyin:

lib/main.dart

  Future<void> init() async {
    await Firebase.initializeApp(
        options: DefaultFirebaseOptions.currentPlatform);

    FirebaseUIAuth.configureProviders([
      EmailAuthProvider(),
    ]);

    // Add from here
    FirebaseFirestore.instance
        .collection('attendees')
        .where('attending', isEqualTo: true)
        .snapshots()
        .listen((snapshot) {
      _attendees = snapshot.docs.length;
      notifyListeners();
    });
    // To here

    FirebaseAuth.instance.userChanges().listen((user) {
      if (user != null) {
        _loginState = ApplicationLoginState.loggedIn;
        _guestBookSubscription = FirebaseFirestore.instance
            .collection('guestbook')
            .orderBy('timestamp', descending: true)
            .snapshots()
            .listen((snapshot) {
          _guestBookMessages = [];
          for (final document in snapshot.docs) {
            _guestBookMessages.add(
              GuestBookMessage(
                name: document.data()['name'] as String,
                message: document.data()['text'] as String,
              ),
            );
          }
          notifyListeners();
        });
        // Add from here
        _attendingSubscription = FirebaseFirestore.instance
            .collection('attendees')
            .doc(user.uid)
            .snapshots()
            .listen((snapshot) {
          if (snapshot.data() != null) {
            if (snapshot.data()!['attending'] as bool) {
              _attending = Attending.yes;
            } else {
              _attending = Attending.no;
            }
          } else {
            _attending = Attending.unknown;
          }
          notifyListeners();
        });
        // to here
      } else {
        _loginState = ApplicationLoginState.loggedOut;
        _guestBookMessages = [];
        _guestBookSubscription?.cancel();
        _attendingSubscription?.cancel(); // new
      }
      notifyListeners();
    });
  }

Yukarıdakiler, katılımcı sayısını bulmak için her zaman abone olunan bir sorgu ve yalnızca bir kullanıcı oturum açtığında kullanıcının katılıp katılmadığını öğrenmek için etkin olan ikinci bir sorgu ekler. Ardından, GuestBookMessage bildiriminden sonra aşağıdaki numaralandırmayı ekleyin:

lib/main.dart

enum Attending { yes, no, unknown }

Şimdi eski radyo düğmeleri gibi davranan yeni bir widget tanımlayacaksınız. Ne evet ne de hayır seçili olmadan belirsiz bir durumda başlar, ancak kullanıcı katılıp katılmayacağını seçtiğinde, o seçeneği dolu bir düğmeyle vurgulanmış olarak gösterirsiniz ve diğer seçenek düz bir işleme ile geri çekilir.

lib/main.dart

class YesNoSelection extends StatelessWidget {
  const YesNoSelection(
      {super.key, required this.state, required this.onSelection});
  final Attending state;
  final void Function(Attending selection) onSelection;

  @override
  Widget build(BuildContext context) {
    switch (state) {
      case Attending.yes:
        return Padding(
          padding: const EdgeInsets.all(8.0),
          child: Row(
            children: [
              ElevatedButton(
                style: ElevatedButton.styleFrom(elevation: 0),
                onPressed: () => onSelection(Attending.yes),
                child: const Text('YES'),
              ),
              const SizedBox(width: 8),
              TextButton(
                onPressed: () => onSelection(Attending.no),
                child: const Text('NO'),
              ),
            ],
          ),
        );
      case Attending.no:
        return Padding(
          padding: const EdgeInsets.all(8.0),
          child: Row(
            children: [
              TextButton(
                onPressed: () => onSelection(Attending.yes),
                child: const Text('YES'),
              ),
              const SizedBox(width: 8),
              ElevatedButton(
                style: ElevatedButton.styleFrom(elevation: 0),
                onPressed: () => onSelection(Attending.no),
                child: const Text('NO'),
              ),
            ],
          ),
        );
      default:
        return Padding(
          padding: const EdgeInsets.all(8.0),
          child: Row(
            children: [
              StyledButton(
                onPressed: () => onSelection(Attending.yes),
                child: const Text('YES'),
              ),
              const SizedBox(width: 8),
              StyledButton(
                onPressed: () => onSelection(Attending.no),
                child: const Text('NO'),
              ),
            ],
          ),
        );
    }
  }
}

Daha sonra, oturum açmış bir kullanıcının katılıp katılmadığını aday göstermesini sağlayan YesNoSelection yararlanmak için HomePage oluşturma yöntemini güncellemeniz gerekir. Ayrıca bu etkinlik için katılımcı sayısını da göstereceksiniz.

lib/main.dart

Consumer<ApplicationState>(
  builder: (context, appState, _) => Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      // Add from here
      if (appState.attendees >= 2)
        Paragraph('${appState.attendees} people going')
      else if (appState.attendees == 1)
        const Paragraph('1 person going')
      else
        const Paragraph('No one going'),
      // To here.
      if (appState.loggedIn) ...[
        // Add from here
        YesNoSelection(
          state: appState.attending,
          onSelection: (attending) => appState.attending = attending,
        ),
        // To here.
        const Header('Discussion'),
        GuestBook(
          addMessage: (message) =>
              appState.addMessageToGuestBook(message),
          messages: appState.guestBookMessages,
        ),
      ],
    ],
  ),
),

Kural ekle

Halihazırda ayarlanmış bazı kurallarınız olduğundan, düğmelerle eklediğiniz yeni veriler reddedilecektir. attendees koleksiyonuna eklemeye izin vermek için kuralları güncellemeniz gerekir.

attendees koleksiyonu için, belge adı olarak Kimlik Doğrulama uid kullandığınızdan, onu alabilir ve göndericinin kullanıcı kimliğinin yazdıkları belgeyle aynı olduğunu doğrulayabilirsiniz. Herkesin katılımcı listesini okumasına izin vereceksiniz (orada özel veri olmadığından), ancak yalnızca içerik oluşturucu bunu güncelleyebilmelidir.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // ... //
    match /attendees/{userId} {
      allow read: if true;
      allow write: if request.auth.uid == userId;
    }
  }
}

Doğrulama kuralları ekle

Belgede beklenen tüm alanların mevcut olduğundan emin olmak için veri doğrulaması ekleyin:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // ... //
    match /attendees/{userId} {
      allow read: if true;
      allow write: if request.auth.uid == userId
          && "attending" in request.resource.data;

    }
  }
}

(İsteğe bağlı) Artık düğmelere tıklamanın sonuçlarını görüntüleyebilirsiniz. Firebase konsolunda Cloud Firestore kontrol panelinize gidin.

Uygulama önizlemesi

10. Tebrikler!

Etkileşimli, gerçek zamanlı bir web uygulaması oluşturmak için Firebase'i kullandınız!

Neyi kapsadık

  • Firebase Kimlik Doğrulaması
  • Bulut Firestore
  • Firebase Güvenlik Kuralları

Sonraki adımlar

  • Diğer Firebase ürünleri hakkında daha fazla bilgi edinmek ister misiniz? Belki de kullanıcıların yüklediği resim dosyalarını saklamak istiyorsunuz? Veya kullanıcılarınıza bildirim göndermek mi? Firebase belgelerine göz atın. Firebase için Flutter eklentileri hakkında daha fazla bilgi edinmek ister misiniz? Daha fazla bilgi için FlutterFire'a göz atın.
  • Cloud Firestore hakkında daha fazla bilgi edinmek ister misiniz? Belki alt koleksiyonlar ve işlemler hakkında bilgi edinmek istersiniz? Cloud Firestore'da daha derinlere inen bir kod laboratuvarı için Cloud Firestore web kod laboratuvarına gidin. Veya Cloud Firestore'u tanımak için bu YouTube serisine göz atın!

Daha fazla bilgi edin

Nasıl gitti?

Geri bildiriminizi çok isteriz! Lütfen burada (çok) kısa bir form doldurun.