Flutter এর জন্য Firebase জানুন

1. আপনি শুরু করার আগে

এই কোডল্যাবে, আপনি Android এবং iOS-এর জন্য Flutter মোবাইল অ্যাপ তৈরি করতে Firebase- এর কিছু মৌলিক বিষয় শিখবেন।

পূর্বশর্ত

আপনি কি শিখবেন

  • কিভাবে একটি ইভেন্ট RSVP এবং গেস্টবুক চ্যাট অ্যাপ তৈরি করবেন Android, iOS, Web, এবং macOS-এ Flutter সহ।
  • Firebase প্রমাণীকরণ এবং Firestore-এর সাথে ডেটা সিঙ্ক করে কীভাবে ব্যবহারকারীদের প্রমাণীকরণ করা যায়।

অ্যান্ড্রয়েডে অ্যাপটির হোম স্ক্রীন

iOS-এ অ্যাপের হোম স্ক্রীন

আপনি কি প্রয়োজন হবে

নিম্নলিখিত ডিভাইসগুলির যেকোনো একটি:

এছাড়াও আপনি নিম্নলিখিত প্রয়োজন:

  • আপনার পছন্দের একটি ব্রাউজার, যেমন Google Chrome।
  • আপনার পছন্দের একটি IDE বা পাঠ্য সম্পাদক যা Android স্টুডিও বা ভিজ্যুয়াল স্টুডিও কোডের মতো ডার্ট এবং ফ্লাটার প্লাগইনগুলির সাথে কনফিগার করা হয়েছে৷
  • যদি আপনি প্রান্তে বসবাস উপভোগ করেন তবে ফ্লটার বা beta সর্বশেষ stable সংস্করণ।
  • আপনার ফায়ারবেস প্রকল্প তৈরি এবং পরিচালনার জন্য একটি Google অ্যাকাউন্ট।
  • Firebase CLI আপনার Google অ্যাকাউন্টে লগ ইন করেছে।

2. নমুনা কোড পান

GitHub থেকে আপনার প্রকল্পের প্রাথমিক সংস্করণ ডাউনলোড করুন:

  1. কমান্ড লাইন থেকে, flutter-codelabs ডিরেক্টরিতে গিটহাব সংগ্রহস্থল ক্লোন করুন:
git clone https://github.com/flutter/codelabs.git flutter-codelabs

flutter-codelabs ডিরেক্টরিতে কোডল্যাবগুলির একটি সংগ্রহের জন্য কোড রয়েছে। এই কোডল্যাবের কোডটি flutter-codelabs/firebase-get-to-know-flutter ডিরেক্টরিতে রয়েছে। ডিরেক্টরিটিতে একটি সিরিজের স্ন্যাপশট রয়েছে যা দেখায় যে প্রতিটি ধাপের শেষে আপনার প্রকল্পটি কেমন হওয়া উচিত। উদাহরণস্বরূপ, আপনি দ্বিতীয় ধাপে আছেন।

  1. দ্বিতীয় ধাপের জন্য মিলে যাওয়া ফাইলগুলি খুঁজুন:
cd flutter-codelabs/firebase-get-to-know-flutter/step_02

আপনি যদি এড়িয়ে যেতে চান বা একটি ধাপের পরে কীভাবে কিছু দেখা উচিত তা দেখতে চান, আপনি যে ধাপে আগ্রহী সেই ধাপের নাম অনুসারে নির্দেশিকাটি দেখুন।

স্টার্টার অ্যাপ আমদানি করুন

  • আপনার পছন্দের IDE-এ flutter-codelabs/firebase-get-to-know-flutter/step_02 ডিরেক্টরি খুলুন বা আমদানি করুন। এই ডিরেক্টরিতে কোডল্যাবের জন্য স্টার্টার কোড রয়েছে, যেটিতে এখনও কার্যকরী নয় ফ্লাটার মিটআপ অ্যাপ রয়েছে।

কাজ করা প্রয়োজন যে ফাইলগুলি সনাক্ত করুন

এই অ্যাপের কোড একাধিক ডিরেক্টরিতে ছড়িয়ে আছে। কার্যকারিতার এই বিভাজনটি কাজকে সহজ করে তোলে কারণ এটি কার্যকারিতা অনুসারে কোডকে গোষ্ঠীভুক্ত করে।

  • নিম্নলিখিত ফাইলগুলি সনাক্ত করুন:
    • lib/main.dart : এই ফাইলটিতে প্রধান এন্ট্রি পয়েন্ট এবং অ্যাপ উইজেট রয়েছে।
    • lib/home_page.dart : এই ফাইলটিতে হোম পেজ উইজেট রয়েছে।
    • lib/src/widgets.dart : অ্যাপের স্টাইলকে মানসম্মত করতে সাহায্য করার জন্য এই ফাইলটিতে কয়েকটি উইজেট রয়েছে। তারা স্টার্টার অ্যাপের স্ক্রিন রচনা করে।
    • lib/src/authentication.dart : এই ফাইলটিতে ফায়ারবেস ইমেল-ভিত্তিক প্রমাণীকরণের জন্য লগইন ব্যবহারকারীর অভিজ্ঞতা তৈরি করতে উইজেটের একটি সেট সহ প্রমাণীকরণের একটি আংশিক বাস্তবায়ন রয়েছে। প্রমাণীকরণ প্রবাহের জন্য এই উইজেটগুলি এখনও স্টার্টার অ্যাপে ব্যবহার করা হয়নি, তবে আপনি শীঘ্রই এগুলি যুক্ত করবেন৷

বাকি অ্যাপ তৈরি করার জন্য প্রয়োজন অনুযায়ী আপনি অতিরিক্ত ফাইল যোগ করুন।

lib/main.dart ফাইলটি পর্যালোচনা করুন

এই অ্যাপটি পুরো অ্যাপ জুড়ে রোবোটোকে ডিফল্ট ফন্ট করতে google_fonts প্যাকেজের সুবিধা নেয়। আপনি fonts.google.com অন্বেষণ করতে পারেন এবং অ্যাপের বিভিন্ন অংশে আপনি সেখানে যে ফন্টগুলি আবিষ্কার করেন তা ব্যবহার করতে পারেন৷

আপনি lib/src/widgets.dart ফাইল থেকে Header , Paragraph এবং IconAndDetail আকারে সাহায্যকারী উইজেটগুলি ব্যবহার করেন। HomePage বর্ণিত পৃষ্ঠা বিন্যাসে বিশৃঙ্খলা কমাতে এই উইজেটগুলি ডুপ্লিকেটেড কোড বাদ দেয়। এটি একটি সামঞ্জস্যপূর্ণ চেহারা এবং অনুভূতি সক্ষম করে।

Android, iOS, ওয়েব এবং macOS-এ আপনার অ্যাপটি দেখতে কেমন তা এখানে রয়েছে:

অ্যান্ড্রয়েডে অ্যাপটির হোম স্ক্রীন

iOS-এ অ্যাপের হোম স্ক্রীন

ওয়েবে অ্যাপের হোম স্ক্রীন

MacOS-এ অ্যাপের হোম স্ক্রীন

3. একটি ফায়ারবেস প্রকল্প তৈরি এবং কনফিগার করুন৷

ইভেন্টের তথ্য প্রদর্শন আপনার অতিথিদের জন্য দুর্দান্ত, কিন্তু এটি নিজে থেকে কারও জন্য খুব দরকারী নয়। আপনাকে অ্যাপটিতে কিছু গতিশীল কার্যকারিতা যোগ করতে হবে। এটি করতে, আপনাকে আপনার অ্যাপের সাথে Firebase সংযোগ করতে হবে। Firebase এর সাথে শুরু করতে, আপনাকে একটি Firebase প্রকল্প তৈরি এবং কনফিগার করতে হবে।

একটি ফায়ারবেস প্রকল্প তৈরি করুন

  1. Firebase এ সাইন ইন করুন।
  2. কনসোলে, প্রকল্প যোগ করুন বা একটি প্রকল্প তৈরি করুন ক্লিক করুন।
  3. প্রকল্পের নাম ক্ষেত্রে, Firebase-Flutter-Codelab লিখুন এবং তারপর Continue-এ ক্লিক করুন।

4395e4e67c08043a.png

  1. প্রকল্প তৈরির বিকল্পগুলির মাধ্যমে ক্লিক করুন। অনুরোধ করা হলে, Firebase শর্তাবলী স্বীকার করুন, কিন্তু Google Analytics এর সেটআপ এড়িয়ে যান কারণ আপনি এটি এই অ্যাপের জন্য ব্যবহার করবেন না।

b7138cde5f2c7b61.png

ফায়ারবেস প্রকল্পগুলি সম্পর্কে আরও জানতে, ফায়ারবেস প্রকল্পগুলি বুঝতে দেখুন।

অ্যাপটি নিম্নলিখিত Firebase পণ্যগুলি ব্যবহার করে, যা ওয়েব অ্যাপের জন্য উপলব্ধ:

  • প্রমাণীকরণ: ব্যবহারকারীদের আপনার অ্যাপে সাইন ইন করতে দেয়।
  • ফায়ারস্টোর: ক্লাউডে স্ট্রাকচার্ড ডেটা সংরক্ষণ করে এবং ডেটা পরিবর্তন হলে তাৎক্ষণিক বিজ্ঞপ্তি পায়।
  • ফায়ারবেস নিরাপত্তা নিয়ম: আপনার ডাটাবেস সুরক্ষিত করে।

এই পণ্যগুলির মধ্যে কিছুর জন্য বিশেষ কনফিগারেশন প্রয়োজন বা আপনাকে Firebase কনসোলে সেগুলি সক্ষম করতে হবে৷

ইমেল সাইন-ইন প্রমাণীকরণ সক্ষম করুন৷

  1. ফায়ারবেস কনসোলের প্রজেক্ট ওভারভিউ প্যানে, বিল্ড মেনুটি প্রসারিত করুন।
  2. প্রমাণীকরণ > শুরু করুন > সাইন-ইন পদ্ধতি > ইমেল/পাসওয়ার্ড > সক্ষম > সংরক্ষণ ক্লিক করুন।

58e3e3e23c2f16a4.png

Firestore সক্ষম করুন

ওয়েব অ্যাপটি চ্যাট মেসেজ সেভ করতে এবং নতুন চ্যাট মেসেজ পেতে Firestore ব্যবহার করে।

Firestore সক্ষম করুন:

  • বিল্ড মেনুতে, ফায়ারস্টোর ডেটাবেস > ডেটাবেস তৈরি করুন ক্লিক করুন।

99e8429832d23fa3.png

  1. স্টার্ট ইন টেস্ট মোডে নির্বাচন করুন এবং তারপর নিরাপত্তা নিয়ম সম্পর্কে দাবিত্যাগ পড়ুন। টেস্ট মোড নিশ্চিত করে যে আপনি বিকাশের সময় অবাধে ডাটাবেসে লিখতে পারেন।

6be00e26c72ea032.png

  1. পরবর্তী ক্লিক করুন এবং তারপর আপনার ডাটাবেসের জন্য অবস্থান নির্বাচন করুন. আপনি ডিফল্ট ব্যবহার করতে পারেন. আপনি পরে অবস্থান পরিবর্তন করতে পারবেন না.

278656eefcfb0216.png

  1. সক্ষম করুন ক্লিক করুন।

4. ফায়ারবেস কনফিগার করুন

Flutter এর সাথে Firebase ব্যবহার করার জন্য, FlutterFire লাইব্রেরিগুলিকে সঠিকভাবে ব্যবহার করার জন্য Flutter প্রোজেক্ট কনফিগার করার জন্য আপনাকে নিম্নলিখিত কাজগুলি সম্পূর্ণ করতে হবে:

  1. আপনার প্রকল্পে FlutterFire নির্ভরতা যোগ করুন।
  2. Firebase প্রকল্পে পছন্দসই প্ল্যাটফর্ম নিবন্ধন করুন৷
  3. প্ল্যাটফর্ম-নির্দিষ্ট কনফিগারেশন ফাইলটি ডাউনলোড করুন এবং তারপর কোডে যোগ করুন।

আপনার ফ্লাটার অ্যাপের শীর্ষ-স্তরের ডিরেক্টরিতে, android , ios , macos এবং web সাবডিরেক্টরি রয়েছে, যেগুলি যথাক্রমে iOS এবং Android-এর জন্য প্ল্যাটফর্ম-নির্দিষ্ট কনফিগারেশন ফাইলগুলি ধারণ করে৷

নির্ভরতা কনফিগার করুন

আপনি এই অ্যাপে যে দুটি ফায়ারবেস পণ্য ব্যবহার করেন তার জন্য আপনাকে FlutterFire লাইব্রেরি যোগ করতে হবে: প্রমাণীকরণ এবং Firestore।

  • কমান্ড লাইন থেকে, নিম্নলিখিত নির্ভরতা যোগ করুন:
$ flutter pub add firebase_core

firebase_core প্যাকেজ হল সমস্ত Firebase Flutter প্লাগইনগুলির জন্য প্রয়োজনীয় সাধারণ কোড৷

$ flutter pub add firebase_auth

firebase_auth প্যাকেজ প্রমাণীকরণের সাথে ইন্টিগ্রেশন সক্ষম করে।

$ flutter pub add cloud_firestore

cloud_firestore প্যাকেজ ফায়ারস্টোর ডেটা স্টোরেজে অ্যাক্সেস সক্ষম করে।

$ flutter pub add provider

firebase_ui_auth প্যাকেজ প্রমাণীকরণ প্রবাহের সাথে বিকাশকারীর গতি বাড়ানোর জন্য উইজেট এবং ইউটিলিটিগুলির একটি সেট সরবরাহ করে।

$ flutter pub add firebase_ui_auth

আপনি প্রয়োজনীয় প্যাকেজগুলি যোগ করেছেন, কিন্তু উপযুক্তভাবে Firebase ব্যবহার করার জন্য আপনাকে iOS, Android, macOS এবং ওয়েব রানার প্রকল্পগুলিও কনফিগার করতে হবে। আপনি provider প্যাকেজটিও ব্যবহার করেন যা প্রদর্শন যুক্তি থেকে ব্যবসায়িক যুক্তিকে আলাদা করতে সক্ষম করে।

FlutterFire CLI ইনস্টল করুন

FlutterFire CLI অন্তর্নিহিত Firebase CLI এর উপর নির্ভর করে।

  1. যদি আপনি ইতিমধ্যে এটি না করে থাকেন, তাহলে আপনার মেশিনে Firebase CLI ইনস্টল করুন।
  2. FlutterFire CLI ইনস্টল করুন:
$ dart pub global activate flutterfire_cli

একবার ইনস্টল হয়ে গেলে, flutterfire কমান্ড বিশ্বব্যাপী উপলব্ধ।

আপনার অ্যাপস কনফিগার করুন

একটি নির্দিষ্ট প্ল্যাটফর্মের জন্য সমস্ত কনফিগারেশন তৈরি করতে CLI আপনার Firebase প্রকল্প এবং নির্বাচিত প্রকল্প অ্যাপ থেকে তথ্য বের করে।

আপনার অ্যাপের রুটে, configure কমান্ডটি চালান:

$ flutterfire configure

কনফিগারেশন কমান্ড আপনাকে নিম্নলিখিত প্রক্রিয়াগুলির মাধ্যমে গাইড করে:

  1. .firebaserc ফাইলের উপর ভিত্তি করে বা Firebase কনসোল থেকে একটি Firebase প্রকল্প নির্বাচন করুন।
  2. কনফিগারেশনের জন্য প্ল্যাটফর্ম নির্ধারণ করুন, যেমন Android, iOS, macOS এবং ওয়েব।
  3. Firebase অ্যাপ্লিকেশানগুলি সনাক্ত করুন যেগুলি থেকে কনফিগারেশন বের করতে হবে৷ ডিফল্টরূপে, CLI আপনার বর্তমান প্রজেক্ট কনফিগারেশনের উপর ভিত্তি করে স্বয়ংক্রিয়ভাবে Firebase অ্যাপের সাথে মিলিত হওয়ার চেষ্টা করে।
  4. আপনার প্রকল্পে একটি firebase_options.dart ফাইল তৈরি করুন।

macOS কনফিগার করুন

macOS-এ ফ্লটার সম্পূর্ণরূপে স্যান্ডবক্সযুক্ত অ্যাপ তৈরি করে। যেহেতু এই অ্যাপটি Firebase সার্ভারের সাথে যোগাযোগ করার জন্য নেটওয়ার্কের সাথে একীভূত হয়, তাই আপনাকে নেটওয়ার্ক ক্লায়েন্ট বিশেষাধিকারের সাথে আপনার অ্যাপটি কনফিগার করতে হবে।

macos/Runner/DebugProfile.entitlements

<?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.entitlements

<?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>

আরও তথ্যের জন্য, ফ্লটারের জন্য ডেস্কটপ সমর্থন দেখুন।

5. RSVP কার্যকারিতা যোগ করুন

এখন যেহেতু আপনি অ্যাপটিতে Firebase যোগ করেছেন, আপনি একটি RSVP বোতাম তৈরি করতে পারেন যা প্রমাণীকরণের সাথে লোকেদের নিবন্ধন করে। অ্যান্ড্রয়েড নেটিভ, আইওএস নেটিভ এবং ওয়েবের জন্য, প্রিবিল্ট FirebaseUI Auth প্যাকেজ রয়েছে, তবে আপনাকে ফ্লটারের জন্য এই ক্ষমতা তৈরি করতে হবে।

আপনি যে প্রকল্পটি আগে পুনরুদ্ধার করেছিলেন তাতে উইজেটের একটি সেট অন্তর্ভুক্ত ছিল যা বেশিরভাগ প্রমাণীকরণ প্রবাহের জন্য ব্যবহারকারী ইন্টারফেস প্রয়োগ করে। আপনি অ্যাপের সাথে প্রমাণীকরণকে সংহত করতে ব্যবসায়িক যুক্তি প্রয়োগ করেন।

Provider প্যাকেজের সাথে ব্যবসায়িক যুক্তি যোগ করুন

ফ্লাটার উইজেটের অ্যাপের ট্রি জুড়ে একটি কেন্দ্রীভূত অ্যাপ স্টেট অবজেক্ট উপলব্ধ করতে provider প্যাকেজটি ব্যবহার করুন:

  1. নিম্নলিখিত সামগ্রী সহ app_state.dart নামে একটি নতুন ফাইল তৈরি করুন:

lib/app_state.dart

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

import 'firebase_options.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();
    });
  }
}

import বিবৃতিগুলি Firebase Core এবং Auth-এর পরিচয় দেয়, provider প্যাকেজটি টান করে যা অ্যাপ স্টেট অবজেক্টকে উইজেট ট্রি জুড়ে উপলব্ধ করে এবং firebase_ui_auth প্যাকেজ থেকে প্রমাণীকরণ উইজেটগুলি অন্তর্ভুক্ত করে।

এই ApplicationState অ্যাপ্লিকেশান স্টেট অবজেক্টের এই পদক্ষেপের জন্য একটি প্রধান দায়িত্ব রয়েছে, যা উইজেট ট্রিকে সতর্ক করা যে একটি প্রমাণীকৃত অবস্থায় একটি আপডেট আছে।

অ্যাপটিতে ব্যবহারকারীর লগইন অবস্থার অবস্থা জানাতে আপনি শুধুমাত্র একটি প্রদানকারী ব্যবহার করেন। একজন ব্যবহারকারীকে লগ ইন করতে দিতে, আপনি firebase_ui_auth প্যাকেজ দ্বারা প্রদত্ত UI ব্যবহার করেন, যা আপনার অ্যাপে লগইন স্ক্রীন দ্রুত বুটস্ট্র্যাপ করার একটি দুর্দান্ত উপায়।

প্রমাণীকরণ প্রবাহকে একীভূত করুন

  1. lib/main.dart ফাইলের শীর্ষে আমদানি পরিবর্তন করুন:

lib/main.dart

import 'package:firebase_ui_auth/firebase_ui_auth.dart'; // new
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';               // new
import 'package:google_fonts/google_fonts.dart';
import 'package:provider/provider.dart';                 // new

import 'app_state.dart';                                 // new
import 'home_page.dart';
  1. অ্যাপ্লিকেশান আরম্ভের সাথে অ্যাপ্লিকেশানের অবস্থা সংযুক্ত করুন এবং তারপর HomePage প্রমাণীকরণ প্রবাহ যোগ করুন:

lib/main.dart

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

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

main() ফাংশনে পরিবর্তন প্রদানকারী প্যাকেজটিকে ChangeNotifierProvider উইজেট সহ অ্যাপ স্টেট অবজেক্টের ইনস্ট্যান্টেশনের জন্য দায়ী করে। আপনি এই নির্দিষ্ট provider শ্রেণীটি ব্যবহার করেন কারণ অ্যাপ স্টেট অবজেক্ট ChangeNotifier ক্লাসকে প্রসারিত করে, যা provider প্যাকেজকে জানতে দেয় কখন নির্ভরশীল উইজেটগুলি পুনরায় প্রদর্শন করতে হবে।

  1. একটি GoRouter কনফিগারেশন তৈরি করে FirebaseUI আপনার জন্য প্রদান করে এমন বিভিন্ন স্ক্রিনে নেভিগেশন পরিচালনা করতে আপনার অ্যাপ আপডেট করুন:

lib/main.dart

// Add GoRouter configuration outside the App class
final _router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => const HomePage(),
      routes: [
        GoRoute(
          path: 'sign-in',
          builder: (context, state) {
            return SignInScreen(
              actions: [
                ForgotPasswordAction(((context, email) {
                  final uri = Uri(
                    path: '/sign-in/forgot-password',
                    queryParameters: <String, String?>{
                      'email': email,
                    },
                  );
                  context.push(uri.toString());
                })),
                AuthStateChangeAction(((context, state) {
                  final user = switch (state) {
                    SignedIn state => state.user,
                    UserCreated state => state.credential.user,
                    _ => null
                  };
                  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);
                  }
                  context.pushReplacement('/');
                })),
              ],
            );
          },
          routes: [
            GoRoute(
              path: 'forgot-password',
              builder: (context, state) {
                final arguments = state.uri.queryParameters;
                return ForgotPasswordScreen(
                  email: arguments['email'],
                  headerMaxExtent: 200,
                );
              },
            ),
          ],
        ),
        GoRoute(
          path: 'profile',
          builder: (context, state) {
            return ProfileScreen(
              providers: const [],
              actions: [
                SignedOutAction((context) {
                  context.pushReplacement('/');
                }),
              ],
            );
          },
        ),
      ],
    ),
  ],
);
// end of GoRouter configuration

// Change MaterialApp to MaterialApp.router and add the routerConfig
class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      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,
        useMaterial3: true,
      ),
      routerConfig: _router, // new
    );
  }
}

প্রমাণীকরণ প্রবাহের নতুন অবস্থার উপর ভিত্তি করে প্রতিটি স্ক্রিনের সাথে যুক্ত একটি ভিন্ন ধরণের ক্রিয়া রয়েছে। প্রমাণীকরণে বেশিরভাগ রাজ্য পরিবর্তনের পরে, আপনি একটি পছন্দের স্ক্রীনে ফিরে যেতে পারেন, তা হোম স্ক্রীন হোক বা অন্য স্ক্রীন, যেমন প্রোফাইল।

  1. HomePage ক্লাসের বিল্ড পদ্ধতিতে, অ্যাপ স্টেটকে AuthFunc উইজেটের সাথে একীভূত করুন:

lib/home_page.dart

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

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

class HomePage extends StatelessWidget {
  const HomePage({super.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'),
          // 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 উইজেটটি ইনস্ট্যান্টিয়েট করুন এবং এটি একটি Consumer উইজেটে মোড়ানো। উপভোক্তা উইজেট হল একটি সাধারণ উপায় যেটি provider প্যাকেজটি যখন অ্যাপের অবস্থা পরিবর্তিত হয় তখন গাছের অংশ পুনর্নির্মাণ করতে ব্যবহার করা যেতে পারে। AuthFunc উইজেট হল পরিপূরক উইজেট যা আপনি পরীক্ষা করেন।

প্রমাণীকরণ প্রবাহ পরীক্ষা করুন

cdf2d25e436bd48d.png

  1. অ্যাপে, SignInScreen শুরু করতে RSVP বোতামে ট্যাপ করুন।

2a2cd6d69d172369.png

  1. একটি ইমেইল ঠিকানা প্রবেশ করুন. আপনি ইতিমধ্যে নিবন্ধিত থাকলে, সিস্টেম আপনাকে একটি পাসওয়ার্ড লিখতে অনুরোধ করে। অন্যথায়, সিস্টেম আপনাকে রেজিস্ট্রেশন ফর্মটি পূরণ করতে অনুরোধ করে।

e5e65065dba36b54.png

  1. ত্রুটি-হ্যান্ডলিং প্রবাহ পরীক্ষা করতে ছয় অক্ষরের কম একটি পাসওয়ার্ড লিখুন। আপনি নিবন্ধিত হলে, আপনি পরিবর্তে পাসওয়ার্ড দেখতে পাবেন.
  2. ত্রুটি-হ্যান্ডলিং প্রবাহ পরীক্ষা করতে ভুল পাসওয়ার্ড লিখুন।
  3. সঠিক পাসওয়ার্ড দিন। আপনি লগ-ইন অভিজ্ঞতা দেখতে পাচ্ছেন, যা ব্যবহারকারীকে লগ আউট করার ক্ষমতা দেয়।

4ed811a25b0cf816.png

6. ফায়ারস্টোরে বার্তা লিখুন

ব্যবহারকারীরা আসছেন জেনে দারুণ লাগছে, কিন্তু অ্যাপটিতে আপনাকে অতিথিদের অন্য কিছু দিতে হবে। যদি তারা একটি গেস্টবুকে বার্তা রেখে যেতে পারে? তারা ভাগ করে নিতে পারে কেন তারা আসতে আগ্রহী বা তারা কার সাথে দেখা করতে চায়।

ব্যবহারকারীরা অ্যাপে যে চ্যাট বার্তাগুলি লেখেন সেগুলি সংরক্ষণ করতে, আপনি Firestore ব্যবহার করুন৷

তথ্য মডেল

Firestore হল একটি NoSQL ডাটাবেস, এবং ডাটাবেসে সংরক্ষিত ডেটা সংগ্রহ, নথি, ক্ষেত্র এবং উপ-সংকলনে বিভক্ত করা হয়। আপনি চ্যাটের প্রতিটি বার্তা একটি নথি হিসাবে একটি guestbook সংগ্রহে সংরক্ষণ করেন, যা একটি শীর্ষ-স্তরের সংগ্রহ।

7c20dc8424bb1d84.png

Firestore এ বার্তা যোগ করুন

এই বিভাগে, আপনি ডাটাবেসে বার্তা লিখতে ব্যবহারকারীদের জন্য কার্যকারিতা যোগ করুন। প্রথমে, আপনি একটি ফর্ম ক্ষেত্র যোগ করুন এবং বোতাম পাঠান, এবং তারপর আপনি কোড যোগ করুন যা এই উপাদানগুলিকে ডাটাবেসের সাথে সংযুক্ত করে।

  1. guest_book.dart নামে একটি নতুন ফাইল তৈরি করুন, একটি বার্তা ক্ষেত্রের UI উপাদান এবং একটি পাঠান বোতাম তৈরি করতে একটি GuestBook স্টেটফুল উইজেট যোগ করুন:

lib/guest_book.dart

import 'dart:async';

import 'package:flutter/material.dart';

import 'src/widgets.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'),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

এখানে আগ্রহের কয়েকটি পয়েন্ট রয়েছে। প্রথমত, আপনি একটি ফর্ম ইনস্ট্যান্টিয়েট করেন যাতে আপনি যাচাই করতে পারেন যে বার্তাটিতে আসলে বিষয়বস্তু রয়েছে এবং ব্যবহারকারীকে একটি ত্রুটির বার্তা দেখাতে পারেন যদি না থাকে। একটি ফর্ম যাচাই করার জন্য, আপনি একটি GlobalKey দিয়ে ফর্মের পিছনে ফর্ম স্টেট অ্যাক্সেস করেন। কী এবং সেগুলি কীভাবে ব্যবহার করবেন সে সম্পর্কে আরও তথ্যের জন্য, কখন কী ব্যবহার করবেন দেখুন।

এছাড়াও নোট করুন যেভাবে উইজেটগুলি সাজানো হয়েছে, আপনার কাছে একটি TextFormField এবং একটি StyledButton সহ একটি Row রয়েছে, যেটিতে একটি Row রয়েছে। এছাড়াও লক্ষ্য করুন TextFormField একটি Expanded উইজেটে মোড়ানো, যা TextFormField সারিতে অতিরিক্ত স্থান পূরণ করতে বাধ্য করে। কেন এটি প্রয়োজন তা আরও ভালভাবে বোঝার জন্য, বোঝার সীমাবদ্ধতা দেখুন।

এখন আপনার কাছে একটি উইজেট রয়েছে যা ব্যবহারকারীকে অতিথি বইতে যোগ করার জন্য কিছু পাঠ্য প্রবেশ করতে সক্ষম করে, আপনাকে এটি স্ক্রিনে পেতে হবে।

  1. ListView এর বাচ্চাদের শেষে নিম্নলিখিত দুটি লাইন যোগ করতে HomePage মূল অংশটি সম্পাদনা করুন:
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)),

যদিও এটি উইজেট প্রদর্শনের জন্য যথেষ্ট, এটি দরকারী কিছু করার জন্য যথেষ্ট নয়। আপনি শীঘ্রই এই কোডটিকে কার্যকরী করতে আপডেট করুন।

অ্যাপের পূর্বরূপ

চ্যাট ইন্টিগ্রেশন সহ অ্যান্ড্রয়েডে অ্যাপের হোম স্ক্রীন

চ্যাট ইন্টিগ্রেশন সহ iOS-এ অ্যাপের হোম স্ক্রীন

চ্যাট ইন্টিগ্রেশন সহ ওয়েবে অ্যাপের হোম স্ক্রীন

চ্যাট ইন্টিগ্রেশন সহ macOS-এ অ্যাপের হোম স্ক্রীন

যখন একজন ব্যবহারকারী পাঠান ক্লিক করেন, তখন এটি নিম্নলিখিত কোড স্নিপেটটিকে ট্রিগার করে। এটি ডাটাবেসের guestbook সংগ্রহে বার্তা ইনপুট ক্ষেত্রের বিষয়বস্তু যোগ করে। বিশেষভাবে, addMessageToGuestBook পদ্ধতি guestbook সংগ্রহে একটি স্বয়ংক্রিয়ভাবে তৈরি আইডি সহ একটি নতুন নথিতে বার্তা সামগ্রী যোগ করে।

মনে রাখবেন FirebaseAuth.instance.currentUser.uid হল স্বয়ংক্রিয়ভাবে তৈরি হওয়া অনন্য আইডির একটি রেফারেন্স যা প্রমাণীকরণ সমস্ত লগ-ইন ব্যবহারকারীদের জন্য দেয়।

  • lib/app_state.dart ফাইলে, addMessageToGuestBook পদ্ধতি যোগ করুন। আপনি পরবর্তী ধাপে ইউজার ইন্টারফেসের সাথে এই ক্ষমতাটি সংযুক্ত করুন।

lib/app_state.dart

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

import 'firebase_options.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 এবং ডাটাবেস সংযোগ করুন

আপনার কাছে একটি UI আছে যেখানে ব্যবহারকারী অতিথি বইতে যোগ করতে চান এমন পাঠ্য লিখতে পারেন এবং আপনার কাছে Firestore এ এন্ট্রি যোগ করার কোড আছে। এখন আপনাকে যা করতে হবে তা হল দুটি সংযোগ।

  • lib/home_page.dart ফাইলে, HomePage উইজেটে নিম্নলিখিত পরিবর্তন করুন:

lib/home_page.dart

import 'package:firebase_auth/firebase_auth.dart'
    hide EmailAuthProvider, PhoneAuthProvider;
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import 'app_state.dart';
import 'guest_book.dart';                         // new
import 'src/authentication.dart';
import 'src/widgets.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.
        ],
      ),
    );
  }
}

আপনি সম্পূর্ণ বাস্তবায়নের সাথে এই ধাপের শুরুতে যোগ করা দুটি লাইন প্রতিস্থাপন করেছেন। আপনি যে গাছটি রেন্ডার করছেন তার অংশে অ্যাপের অবস্থা উপলব্ধ করতে আপনি আবার Consumer<ApplicationState> ব্যবহার করুন। এটি আপনাকে এমন কাউকে প্রতিক্রিয়া জানাতে দেয় যে UI এ একটি বার্তা প্রবেশ করে এবং এটি ডাটাবেসে প্রকাশ করে। পরবর্তী বিভাগে, আপনি পরীক্ষা করবেন যে যোগ করা বার্তাগুলি ডাটাবেসে প্রকাশিত হয়েছে কিনা।

বার্তা পাঠানোর পরীক্ষা করুন

  1. প্রয়োজনে অ্যাপটিতে সাইন ইন করুন।
  2. একটি বার্তা লিখুন, যেমন Hey there! , এবং তারপর SEND এ ক্লিক করুন।

এই ক্রিয়াটি আপনার Firestore ডাটাবেসে বার্তাটি লেখে। যাইহোক, আপনি আপনার প্রকৃত ফ্লাটার অ্যাপে বার্তাটি দেখতে পাচ্ছেন না কারণ আপনাকে এখনও ডেটা পুনরুদ্ধার বাস্তবায়ন করতে হবে, যা আপনি পরবর্তী ধাপে করবেন। যাইহোক, Firebase কনসোলের ডেটাবেস ড্যাশবোর্ডে , আপনি guestbook সংগ্রহে আপনার যোগ করা বার্তা দেখতে পাবেন। আপনি যদি আরও বার্তা পাঠান, আপনি আপনার guestbook সংগ্রহে আরও নথি যোগ করুন। উদাহরণস্বরূপ, নিম্নলিখিত কোড স্নিপেট দেখুন:

713870af0b3b63c.png

7. বার্তা পড়ুন

এটা চমৎকার যে অতিথিরা ডাটাবেসে বার্তা লিখতে পারে, কিন্তু তারা এখনও অ্যাপে সেগুলি দেখতে পায় না। এটা ঠিক করার সময়!

বার্তা সিঙ্ক্রোনাইজ করুন

বার্তাগুলি প্রদর্শন করার জন্য, আপনাকে এমন শ্রোতাদের যোগ করতে হবে যা ডেটা পরিবর্তনের সময় ট্রিগার করে এবং তারপরে একটি UI উপাদান তৈরি করে যা নতুন বার্তাগুলি দেখায়। আপনি অ্যাপের স্টেটে কোড যোগ করেন যা অ্যাপ থেকে নতুন যোগ করা বার্তা শোনে।

  1. একটি নতুন ফাইল তৈরি করুন guest_book_message.dart , Firestore-এ আপনার সঞ্চয় করা ডেটার একটি কাঠামোগত দৃশ্য প্রকাশ করতে নিম্নলিখিত শ্রেণী যোগ করুন।

lib/guest_book_message.dart

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

  final String name;
  final String message;
}
  1. lib/app_state.dart ফাইলে, নিম্নলিখিত আমদানি যোগ করুন:

lib/app_state.dart

import 'dart:async';                                     // new

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart'
    hide EmailAuthProvider, PhoneAuthProvider;
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_ui_auth/firebase_ui_auth.dart';
import 'package:flutter/material.dart';

import 'firebase_options.dart';
import 'guest_book_message.dart';                        // new
  1. ApplicationState এর বিভাগে যেখানে আপনি স্টেট এবং গেটার সংজ্ঞায়িত করেন, নিম্নলিখিত লাইনগুলি যোগ করুন:

lib/app_state.dart

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

  // Add from here...
  StreamSubscription<QuerySnapshot>? _guestBookSubscription;
  List<GuestBookMessage> _guestBookMessages = [];
  List<GuestBookMessage> get guestBookMessages => _guestBookMessages;
  // ...to here.
  1. ApplicationState এর প্রারম্ভিক বিভাগে, কোনো ব্যবহারকারী লগ ইন করলে এবং লগ আউট করার সময় সদস্যতা ত্যাগ করলে নথি সংগ্রহের বিষয়ে একটি প্রশ্নে সদস্যতা নিতে নিম্নলিখিত লাইনগুলি যোগ করুন:

lib/app_state.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 সংগ্রহের বিষয়ে একটি প্রশ্ন তৈরি করেন এবং এই সংগ্রহে সদস্যতা এবং সদস্যতা ত্যাগ করেন। আপনি স্ট্রীমটি শোনেন, যেখানে আপনি guestbook সংগ্রহে বার্তাগুলির একটি স্থানীয় ক্যাশে পুনর্গঠন করেন এবং এই সদস্যতার একটি রেফারেন্সও সংরক্ষণ করেন যাতে আপনি পরে এটি থেকে সদস্যতা ত্যাগ করতে পারেন। এখানে অনেক কিছু চলছে, তাই একটি পরিষ্কার মানসিক মডেল পেতে কী ঘটবে তা পরিদর্শন করার জন্য আপনার ডিবাগারে এটি অন্বেষণ করা উচিত। আরও তথ্যের জন্য, Firestore এর সাথে রিয়েলটাইম আপডেট পান দেখুন।

  1. lib/guest_book.dart ফাইলে, নিম্নলিখিত আমদানি যোগ করুন:
import 'guest_book_message.dart';
  1. GuestBook উইজেটে, এই পরিবর্তনশীল অবস্থাটিকে ইউজার ইন্টারফেসের সাথে সংযুক্ত করতে কনফিগারেশনের অংশ হিসাবে বার্তাগুলির একটি তালিকা যোগ করুন:

lib/guest_book.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();
}
  1. _GuestBookState এ, এই কনফিগারেশনটি প্রকাশ করতে build পদ্ধতিটি নিম্নরূপ পরিবর্তন করুন:

lib/guest_book.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.
    );
  }
}

আপনি build() পদ্ধতির পূর্ববর্তী বিষয়বস্তু একটি Column উইজেট দিয়ে মুড়েন এবং তারপরে আপনি বার্তার তালিকায় প্রতিটি বার্তার জন্য একটি নতুন Paragraph তৈরি করতে Column শিশুদের লেজের জন্য একটি সংগ্রহ যোগ করেন।

  1. নতুন messages প্যারামিটারের সাথে সঠিকভাবে GuestBook তৈরি করতে HomePage মূল অংশটি আপডেট করুন:

lib/home_page.dart

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

বার্তা সিঙ্ক্রোনাইজেশন পরীক্ষা করুন

Firestore স্বয়ংক্রিয়ভাবে এবং অবিলম্বে ডাটাবেসে সদস্যতা নেওয়া ক্লায়েন্টদের সাথে ডেটা সিঙ্ক্রোনাইজ করে।

বার্তা সিঙ্ক্রোনাইজেশন পরীক্ষা করুন:

  1. অ্যাপে, ডাটাবেসে আপনি আগে তৈরি করা বার্তাগুলি খুঁজুন।
  2. নতুন বার্তা লিখুন। তারা সঙ্গে সঙ্গে হাজির.
  3. একাধিক উইন্ডো বা ট্যাবে আপনার কর্মক্ষেত্র খুলুন। বার্তাগুলি রিয়েল টাইমে উইন্ডো এবং ট্যাব জুড়ে সিঙ্ক হয়।
  4. ঐচ্ছিক: Firebase কনসোলের ডেটাবেস মেনুতে, ম্যানুয়ালি মুছে ফেলুন, পরিবর্তন করুন বা নতুন বার্তা যোগ করুন। সমস্ত পরিবর্তন UI এ প্রদর্শিত হবে।

অভিনন্দন! আপনি আপনার অ্যাপে ফায়ারস্টোর ডকুমেন্ট পড়েন!

অ্যাপের পূর্বরূপ

চ্যাট ইন্টিগ্রেশন সহ অ্যান্ড্রয়েডে অ্যাপের হোম স্ক্রীন

চ্যাট ইন্টিগ্রেশন সহ iOS-এ অ্যাপের হোম স্ক্রীন

চ্যাট ইন্টিগ্রেশন সহ ওয়েবে অ্যাপের হোম স্ক্রীন

চ্যাট ইন্টিগ্রেশন সহ macOS-এ অ্যাপের হোম স্ক্রীন

8. মৌলিক নিরাপত্তা নিয়ম সেট আপ করুন

আপনি প্রাথমিকভাবে পরীক্ষা মোড ব্যবহার করার জন্য Firestore সেট আপ করেছেন, যার অর্থ হল আপনার ডাটাবেস পড়া এবং লেখার জন্য উন্মুক্ত। যাইহোক, আপনার শুধুমাত্র বিকাশের প্রাথমিক পর্যায়ে পরীক্ষা মোড ব্যবহার করা উচিত। একটি সর্বোত্তম অনুশীলন হিসাবে, আপনি আপনার অ্যাপটি বিকাশ করার সাথে সাথে আপনার ডেটাবেসের জন্য সুরক্ষা নিয়ম সেট আপ করা উচিত। নিরাপত্তা আপনার অ্যাপের গঠন এবং আচরণের অবিচ্ছেদ্য অংশ।

ফায়ারবেস নিরাপত্তা বিধি আপনাকে আপনার ডাটাবেসের নথি এবং সংগ্রহগুলিতে অ্যাক্সেস নিয়ন্ত্রণ করতে দেয়। নমনীয় নিয়ম সিনট্যাক্স আপনাকে এমন নিয়ম তৈরি করতে দেয় যা একটি নির্দিষ্ট নথিতে সমস্ত লেখা থেকে পুরো ডাটাবেস থেকে ক্রিয়াকলাপের সাথে মেলে।

মৌলিক নিরাপত্তা নিয়ম সেট আপ করুন:

  1. ফায়ারবেস কনসোলের ডেভেলপ মেনুতে, ডেটাবেস > নিয়ম-এ ক্লিক করুন। আপনি নিম্নলিখিত ডিফল্ট নিরাপত্তা নিয়ম এবং নিয়ম সর্বজনীন হওয়ার বিষয়ে একটি সতর্কতা দেখতে পাবেন:

7767a2d2e64e7275.png

  1. সংগ্রহগুলি সনাক্ত করুন যেখানে অ্যাপটি ডেটা লেখে:

match /databases/{database}/documents , আপনি যে সংগ্রহকে সুরক্ষিত করতে চান তা চিহ্নিত করুন:

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

যেহেতু আপনি প্রতিটি গেস্টবুক নথিতে একটি ক্ষেত্র হিসাবে প্রমাণীকরণ UID ব্যবহার করেছেন, আপনি প্রমাণীকরণ UID পেতে পারেন এবং যাচাই করতে পারেন যে যে কেউ নথিতে লেখার চেষ্টা করছেন তার একটি মিলিত প্রমাণীকরণ UID আছে।

  1. আপনার নিয়ম সেটে পড়ার এবং লেখার নিয়মগুলি যুক্ত করুন:
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;
    }
  }
}

এখন, শুধুমাত্র সাইন-ইন করা ব্যবহারকারীরা অতিথি বইয়ের বার্তাগুলি পড়তে পারেন, তবে শুধুমাত্র একটি বার্তার লেখক একটি বার্তা সম্পাদনা করতে পারেন৷

  1. সমস্ত প্রত্যাশিত ক্ষেত্র নথিতে উপস্থিত রয়েছে তা নিশ্চিত করতে ডেটা যাচাইকরণ যোগ করুন:
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. বোনাস ধাপ: আপনি যা শিখেছেন তা অনুশীলন করুন

একজন অংশগ্রহণকারীর আরএসভিপি স্ট্যাটাস রেকর্ড করুন

এই মুহুর্তে, আপনার অ্যাপটি লোকেদের ইভেন্টে আগ্রহী হলেই তাদের সাথে চ্যাট করার অনুমতি দেয়৷ এছাড়াও, কেউ আসছে কিনা তা আপনি জানেন যখন তারা চ্যাটে বলে।

এই ধাপে, আপনি সংগঠিত হন এবং লোকেদের জানান যে কত লোক আসছে। আপনি অ্যাপ স্টেটে কয়েকটি ক্ষমতা যোগ করুন। প্রথমটি হ'ল লগ-ইন করা ব্যবহারকারীর জন্য মনোনীত করার ক্ষমতা যে তারা অংশগ্রহণ করছে কিনা। দ্বিতীয়টি হল কতজন লোক অংশগ্রহণ করছে তার কাউন্টার।

  1. lib/app_state.dart ফাইলে, ApplicationState এর অ্যাক্সেসর বিভাগে নিম্নলিখিত লাইনগুলি যুক্ত করুন যাতে UI কোড এই অবস্থার সাথে ইন্টারঅ্যাক্ট করতে পারে:

lib/app_state.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});
  }
}
  1. ApplicationState এর init() পদ্ধতিটি নিম্নরূপ আপডেট করুন:

lib/app_state.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) {
        _loggedIn = true;
        _emailVerified = user.emailVerified;
        _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 {
        _loggedIn = false;
        _emailVerified = false;
        _guestBookMessages = [];
        _guestBookSubscription?.cancel();
        _attendingSubscription?.cancel(); // new
      }
      notifyListeners();
    });
  }

এই কোডটি অংশগ্রহণকারীদের সংখ্যা নির্ধারণ করতে একটি সর্বদা-সাবস্ক্রাইব করা ক্যোয়ারী যোগ করে এবং একটি দ্বিতীয় ক্যোয়ারী যা শুধুমাত্র সক্রিয় থাকে যখন একজন ব্যবহারকারী লগ ইন করা থাকে তা নির্ধারণ করতে ব্যবহারকারী অংশগ্রহণ করছেন কিনা।

  1. lib/app_state.dart ফাইলের শীর্ষে নিম্নলিখিত গণনা যোগ করুন।

lib/app_state.dart

enum Attending { yes, no, unknown }
  1. একটি নতুন ফাইল তৈরি করুন yes_no_selection.dart , একটি নতুন উইজেট সংজ্ঞায়িত করুন যা রেডিও বোতামের মতো কাজ করে:

lib/yes_no_selection.dart

import 'package:flutter/material.dart';

import 'app_state.dart';
import 'src/widgets.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: [
              FilledButton(
                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),
              FilledButton(
                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'),
              ),
            ],
          ),
        );
    }
  }
}

এটি একটি অনির্দিষ্ট অবস্থায় শুরু হয় যেখানে হ্যাঁ বা না নির্বাচন করা হয় না। একবার ব্যবহারকারী নির্বাচন করে যে তারা অংশগ্রহণ করছে কিনা, আপনি একটি ভরাট বোতাম দিয়ে হাইলাইট করা সেই বিকল্পটি দেখান এবং অন্য বিকল্পটি একটি ফ্ল্যাট রেন্ডারিং সহ পিছিয়ে যায়।

  1. YesNoSelection এর সুবিধা নিতে HomePage build() পদ্ধতি আপডেট করুন, একজন লগ-ইন করা ব্যবহারকারীকে মনোনীত করতে সক্ষম করুন যে তারা যোগ দিচ্ছেন কিনা, এবং ইভেন্টে অংশগ্রহণকারীদের সংখ্যা প্রদর্শন করুন:

lib/home_page.dart

Consumer<ApplicationState>(
  builder: (context, appState, _) => Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      // Add from here...
      switch (appState.attendees) {
        1 => const Paragraph('1 person going'),
        >= 2 => Paragraph('${appState.attendees} people going'),
        _ => 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,
        ),
      ],
    ],
  ),
),

নিয়ম যোগ করুন

আপনি ইতিমধ্যে কিছু নিয়ম সেট আপ করেছেন, তাই বোতামগুলির সাথে আপনি যে ডেটা যুক্ত করবেন তা প্রত্যাখ্যান করা হবে৷ attendees সংগ্রহে যোগ করার অনুমতি দেওয়ার জন্য আপনাকে নিয়ম আপডেট করতে হবে।

  1. attendees সংগ্রহে, আপনি নথির নাম হিসাবে যে প্রমাণীকরণ ইউআইডি ব্যবহার করেছেন তা ধরুন এবং যাচাই করুন যে জমাদানকারীর uid তারা যে নথিটি লিখছে তার মতোই:
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // ... //
    match /attendees/{userId} {
      allow read: if true;
      allow write: if request.auth.uid == userId;
    }
  }
}

এটি প্রত্যেককে অংশগ্রহণকারীদের তালিকা পড়তে দেয় কারণ সেখানে কোনও ব্যক্তিগত ডেটা নেই, তবে শুধুমাত্র নির্মাতা এটি আপডেট করতে পারেন৷

  1. সমস্ত প্রত্যাশিত ক্ষেত্র নথিতে উপস্থিত রয়েছে তা নিশ্চিত করতে ডেটা যাচাইকরণ যোগ করুন:
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;

    }
  }
}
  1. ঐচ্ছিক: অ্যাপে, Firebase কনসোলে Firestore ড্যাশবোর্ডে ফলাফল দেখতে বোতামে ক্লিক করুন।

অ্যাপের পূর্বরূপ

অ্যান্ড্রয়েডে অ্যাপটির হোম স্ক্রীন

iOS-এ অ্যাপের হোম স্ক্রীন

ওয়েবে অ্যাপের হোম স্ক্রীন

MacOS-এ অ্যাপের হোম স্ক্রীন

10. অভিনন্দন!

আপনি একটি ইন্টারেক্টিভ, রিয়েল-টাইম ওয়েব অ্যাপ তৈরি করতে Firebase ব্যবহার করেছেন!

আরও জানুন