১. শুরু করার আগে
এই কোডল্যাবে আপনি অ্যান্ড্রয়েড এবং আইওএস-এর জন্য ফ্লাটার মোবাইল অ্যাপ তৈরি করতে ফায়ারবেস- এর কিছু প্রাথমিক বিষয় শিখবেন।
পূর্বশর্ত
- ফ্লাটারের সাথে পরিচিতি
- ফ্লাটার এসডিকে
- আপনার পছন্দের একটি টেক্সট এডিটর
আপনি যা শিখবেন
- ফ্লাটার ব্যবহার করে অ্যান্ড্রয়েড, আইওএস, ওয়েব এবং ম্যাকওএস-এ কীভাবে একটি ইভেন্ট আরএসভিপি ও গেস্টবুক চ্যাট অ্যাপ তৈরি করবেন।
- ফায়ারবেস অথেনটিকেশন ব্যবহার করে কীভাবে ব্যবহারকারীদের প্রমাণীকরণ করবেন এবং ফায়ারস্টোরের সাথে ডেটা সিঙ্ক করবেন।
|
|
|
|
আপনার যা যা লাগবে
নিম্নলিখিত ডিভাইসগুলির যেকোনো একটি:
- আপনার কম্পিউটারের সাথে সংযুক্ত এবং ডেভেলপার মোডে সেট করা একটি ফিজিক্যাল অ্যান্ড্রয়েড বা আইওএস ডিভাইস।
- iOS সিমুলেটর (এর জন্য Xcode টুলস প্রয়োজন)।
- অ্যান্ড্রয়েড এমুলেটর ( অ্যান্ড্রয়েড স্টুডিওতে সেটআপ করা প্রয়োজন)।
এছাড়াও আপনার নিম্নলিখিত জিনিসগুলো প্রয়োজন:
- আপনার পছন্দের একটি ব্রাউজার, যেমন গুগল ক্রোম।
- ডার্ট এবং ফ্লাটার প্লাগইন দিয়ে কনফিগার করা আপনার পছন্দের একটি IDE বা টেক্সট এডিটর, যেমন অ্যান্ড্রয়েড স্টুডিও বা ভিজ্যুয়াল স্টুডিও কোড ।
- ফ্লাটারের সর্বশেষ
stableসংস্করণ, অথবা আপনি যদি ঝুঁকি নিতে ভালোবাসেন তবেbeta। - আপনার ফায়ারবেস প্রজেক্ট তৈরি ও পরিচালনার জন্য একটি গুগল অ্যাকাউন্ট।
-
FirebaseCLI আপনার Google অ্যাকাউন্টে লগ ইন করেছে।
২. নমুনা কোডটি নিন।
গিটহাব থেকে আপনার প্রোজেক্টের প্রাথমিক সংস্করণটি ডাউনলোড করুন:
- কমান্ড লাইন থেকে, GitHub রিপোজিটরিটি
flutter-codelabsডিরেক্টরিতে ক্লোন করুন:
git clone https://github.com/flutter/codelabs.git flutter-codelabs
` flutter-codelabs ডিরেক্টরিতে বেশ কিছু কোডল্যাবের কোড থাকে। এই কোডল্যাবের কোডটি flutter-codelabs/firebase-get-to-know-flutter ডিরেক্টরিতে রয়েছে। এই ডিরেক্টরিতে বেশ কিছু স্ন্যাপশট রয়েছে, যা দেখায় প্রতিটি ধাপ শেষে আপনার প্রজেক্টটি কেমন দেখতে হবে। উদাহরণস্বরূপ, আপনি এখন দ্বিতীয় ধাপে আছেন।
- দ্বিতীয় ধাপের জন্য মিলযুক্ত ফাইলগুলো খুঁজুন:
cd flutter-codelabs/firebase-get-to-know-flutter/step_02
যদি আপনি সামনে এগিয়ে যেতে চান অথবা কোনো ধাপের পরে সেটি কেমন দেখাবে তা দেখতে চান, তাহলে আপনার আগ্রহের ধাপটির নামে থাকা ডিরেক্টরিতে দেখুন।
স্টার্টার অ্যাপটি ইম্পোর্ট করুন
- আপনার পছন্দের IDE-তে
flutter-codelabs/firebase-get-to-know-flutter/step_02ডিরেক্টরিটি খুলুন বা ইম্পোর্ট করুন। এই ডিরেক্টরিতে কোডল্যাবের জন্য স্টার্টার কোড রয়েছে, যা একটি এখনও-অকার্যকর ফ্লাটার মিটআপ অ্যাপ। যখন আপনি আপনার IDE-তে অ্যাপটি খুলবেন, তখন আপনি কম্পাইল টাইম এরর দেখতে পাবেন, যা ধাপ ৪-এ ঠিক করা হবে।
যে ফাইলগুলোতে কাজ করা প্রয়োজন, সেগুলো খুঁজে বের করুন।
এই অ্যাপের কোড একাধিক ডিরেক্টরিতে ছড়িয়ে আছে। কাজের এই বিভাজন কাজটিকে সহজ করে তোলে, কারণ এটি কোডকে তার কার্যকারিতা অনুযায়ী শ্রেণিবদ্ধ করে।
- নিম্নলিখিত ফাইলগুলি সনাক্ত করুন:
-
lib/main.dart: এই ফাইলে মূল এন্ট্রি পয়েন্ট এবং অ্যাপ উইজেট থাকে। -
lib/home_page.dart: এই ফাইলে হোম পেজ উইজেটটি রয়েছে। -
lib/src/widgets.dart: এই ফাইলটিতে অ্যাপটির স্টাইলকে মানসম্মত করতে সাহায্য করার জন্য কয়েকটি উইজেট রয়েছে। এগুলো স্টার্টার অ্যাপটির স্ক্রিন তৈরি করে। -
lib/src/authentication.dart: এই ফাইলটিতে অথেনটিকেশনের একটি আংশিক বাস্তবায়ন রয়েছে, যেখানে ফায়ারবেস ইমেল-ভিত্তিক অথেনটিকেশনের জন্য একটি লগইন ইউজার এক্সপেরিয়েন্স তৈরি করার উদ্দেশ্যে কিছু উইজেট দেওয়া আছে। অথেন্টিকেশন ফ্লো-এর জন্য এই উইজেটগুলি এখনও স্টার্টার অ্যাপে ব্যবহৃত হয় না, তবে আপনাকে শীঘ্রই সেগুলি যুক্ত করতে হবে।
-
অ্যাপটির বাকি অংশ তৈরি করার জন্য প্রয়োজন অনুযায়ী আপনি অতিরিক্ত ফাইল যোগ করবেন।
lib/main.dart ফাইলটি পর্যালোচনা করুন।
এই অ্যাপটি google_fonts প্যাকেজ ব্যবহার করে পুরো অ্যাপ জুড়ে Roboto-কে ডিফল্ট ফন্ট হিসেবে সেট করে। আপনি fonts.google.com- এ গিয়ে আপনার খুঁজে পাওয়া ফন্টগুলো অ্যাপের বিভিন্ন অংশে ব্যবহার করতে পারেন।
আপনি lib/src/widgets.dart ফাইল থেকে Header , Paragraph এবং IconAndDetail এই হেল্পার উইজেটগুলো ব্যবহার করেন। এই উইজেটগুলো HomePage এ বর্ণিত পেজ লেআউটে অপ্রয়োজনীয় কোড বাদ দিয়ে বিশৃঙ্খলা কমায়। এটি একটি সামঞ্জস্যপূর্ণ রূপ ও অনুভূতিও নিশ্চিত করে।
অ্যান্ড্রয়েড, আইওএস, ওয়েব এবং ম্যাকওএস-এ আপনার অ্যাপটি দেখতে এইরকম:
|
|
|
|
৩. একটি ফায়ারবেস প্রজেক্ট তৈরি ও সেট আপ করুন।
ইভেন্টের তথ্য প্রদর্শন আপনার অতিথিদের জন্য চমৎকার, কিন্তু এটি নিজে থেকে কারোর জন্যই খুব একটা দরকারি নয়। অ্যাপটিতে আপনাকে কিছু ডাইনামিক কার্যকারিতা যোগ করতে হবে। এটি করার জন্য, আপনাকে আপনার অ্যাপের সাথে ফায়ারবেস (Firebase) সংযোগ করতে হবে। ফায়ারবেস দিয়ে কাজ শুরু করতে, আপনাকে একটি ফায়ারবেস প্রজেক্ট তৈরি এবং সেট আপ করতে হবে।
একটি ফায়ারবেস প্রজেক্ট তৈরি করুন
- আপনার গুগল অ্যাকাউন্ট ব্যবহার করে ফায়ারবেস কনসোলে সাইন ইন করুন।
- নতুন প্রজেক্ট তৈরি করতে বাটনটিতে ক্লিক করুন, এবং তারপর একটি প্রজেক্টের নাম লিখুন (উদাহরণস্বরূপ,
Firebase-Flutter-Codelab)। - চালিয়ে যান-এ ক্লিক করুন।
- অনুরোধ করা হলে, Firebase-এর শর্তাবলী পর্যালোচনা করে গ্রহণ করুন এবং তারপর 'চালিয়ে যান' (Continue ) বোতামে ক্লিক করুন।
- (ঐচ্ছিক) Firebase কনসোলে AI সহায়তা সক্রিয় করুন (Firebase-এ এটিকে "Gemini" বলা হয়)।
- এই কোডল্যাবের জন্য আপনার গুগল অ্যানালিটিক্স-এর প্রয়োজন নেই , তাই গুগল অ্যানালিটিক্স অপশনটি বন্ধ করে দিন ।
- Create project-এ ক্লিক করুন, আপনার প্রজেক্টটি প্রস্তুত হওয়া পর্যন্ত অপেক্ষা করুন, এবং তারপর Continue-তে ক্লিক করুন।
ফায়ারবেস প্রজেক্ট সম্পর্কে আরও জানতে, “ফায়ারবেস প্রজেক্ট বুঝুন” দেখুন।
ফায়ারবেস পণ্য সেট আপ করুন
অ্যাপটি নিম্নলিখিত ফায়ারবেস প্রোডাক্টগুলো ব্যবহার করে, যেগুলো ওয়েব অ্যাপের জন্য উপলব্ধ:
- প্রমাণীকরণ: ব্যবহারকারীদের আপনার অ্যাপে সাইন ইন করতে দেয়।
- ফায়ারস্টোর: ক্লাউডে কাঠামোগত ডেটা সংরক্ষণ করে এবং ডেটা পরিবর্তিত হলে তাৎক্ষণিক বিজ্ঞপ্তি দেয়।
- ফায়ারবেস নিরাপত্তা বিধি: আপনার ডাটাবেসকে সুরক্ষিত করে।
এই পণ্যগুলোর কয়েকটির জন্য বিশেষ কনফিগারেশন প্রয়োজন হয় অথবা আপনাকে ফায়ারবেস কনসোলে সেগুলো সক্রিয় করতে হবে।
ইমেল সাইন-ইন প্রমাণীকরণ সক্রিয় করুন
- Firebase কনসোলের প্রজেক্ট ওভারভিউ প্যানে, বিল্ড মেনুটি এক্সপ্যান্ড করুন।
- প্রমাণীকরণ > শুরু করুন > সাইন-ইন পদ্ধতি > ইমেল/পাসওয়ার্ড > সক্ষম করুন > সংরক্ষণ করুন- এ ক্লিক করুন।

ফায়ারস্টোর সেট আপ করুন
ওয়েব অ্যাপটি চ্যাট বার্তা সংরক্ষণ করতে এবং নতুন চ্যাট বার্তা গ্রহণ করতে ফায়ারস্টোর ব্যবহার করে।
আপনার Firebase প্রোজেক্টে Firestore সেট আপ করার পদ্ধতি নিচে দেওয়া হলো:
- Firebase কনসোলের বাম প্যানেলে, Build প্রসারিত করুন এবং তারপরে Firestore database নির্বাচন করুন।
- ডাটাবেস তৈরি করুন -এ ক্লিক করুন।
- স্ট্যান্ডার্ড সংস্করণ বেছে নিন এবং পরবর্তী ক্লিক করুন।
- ডাটাবেস আইডি
(default)হিসেবেই রাখুন। - আপনার ডেটাবেসের জন্য একটি অবস্থান নির্বাচন করুন, তারপর 'পরবর্তী' বোতামে ক্লিক করুন।
একটি বাস্তব অ্যাপের জন্য, আপনি এমন একটি অবস্থান বেছে নিতে চাইবেন যা আপনার ব্যবহারকারীদের কাছাকাছি। - টেস্ট মোডে স্টার্ট-এ ক্লিক করুন। নিরাপত্তা নিয়মাবলী সম্পর্কিত দাবিত্যাগটি পড়ুন।
এই কোডল্যাবের পরবর্তী অংশে, আপনি আপনার ডেটা সুরক্ষিত করার জন্য সিকিউরিটি রুলস যোগ করবেন। আপনার ডেটাবেসের জন্য সিকিউরিটি রুলস যোগ না করে কোনো অ্যাপ সর্বজনীনভাবে বিতরণ বা প্রকাশ করবেন না । - তৈরি করুন- এ ক্লিক করুন।
৪. ফায়ারবেস কনফিগার করুন
ফ্লাটারের সাথে ফায়ারবেস ব্যবহার করতে, FlutterFire লাইব্রেরিগুলো সঠিকভাবে ব্যবহারের জন্য ফ্লাটার প্রজেক্টটি কনফিগার করতে আপনাকে নিম্নলিখিত কাজগুলো সম্পন্ন করতে হবে:
- আপনার প্রজেক্টে
FlutterFireডিপেন্ডেন্সিগুলো যোগ করুন। - ফায়ারবেস প্রজেক্টে নির্বাচিত প্ল্যাটফর্মটি নিবন্ধন করুন।
- প্ল্যাটফর্ম-নির্দিষ্ট কনফিগারেশন ফাইলটি ডাউনলোড করুন এবং তারপর সেটি কোডে যোগ করুন।
আপনার ফ্লাটার অ্যাপের টপ-লেভেল ডিরেক্টরিতে android , ios , macos এবং web সাবডিরেক্টরি রয়েছে, যেগুলোতে যথাক্রমে iOS এবং Android-এর জন্য প্ল্যাটফর্ম-নির্দিষ্ট কনফিগারেশন ফাইলগুলো থাকে।
নির্ভরতা কনফিগার করুন
এই অ্যাপে ব্যবহৃত দুটি Firebase প্রোডাক্ট—Authentication এবং Firestore—এর জন্য আপনাকে FlutterFire লাইব্রেরি যুক্ত করতে হবে।
- কমান্ড লাইন থেকে, আপনার অ্যাপের রুটে (
.../firebase-get-to-know-flutter/step_02) নিম্নলিখিত ডিপেন্ডেন্সিগুলি যোগ করুন:
$ flutter pub add firebase_core firebase_auth cloud_firestore provider firebase_ui_auth
আপনার ফ্লাটার অ্যাপে ফায়ারবেস ব্যবহার করতে হলে, আপনাকে কয়েকটি বিশেষায়িত প্যাকেজ একত্রিত করতে হবে:
-
firebase_coreপ্যাকেজ : এটিই হলো অপরিহার্য সূচনা বিন্দু। আপনার এই প্যাকেজটি অবশ্যই থাকতে হবে, কারণ ফ্লাটারের জন্য অন্যান্য সমস্ত ফায়ারবেস টুল এর উপর নির্ভরশীল। -
firebase_authপ্যাকেজ : এই প্যাকেজটি ব্যবহারকারীর অ্যাকাউন্ট পরিচালনার জন্য ব্যবহৃত হয়। এর মাধ্যমে আপনি সাইন-আপ, লগইন এবং লগআউটের মতো ফিচার যোগ করতে পারবেন। -
cloud_firestoreপ্যাকেজ : আপনার অ্যাপকে ফায়ারস্টোর ডেটাবেসের সাথে সংযুক্ত করতে এটি ব্যবহার করুন, যার মাধ্যমে আপনি আপনার অ্যাপের ডেটা সংরক্ষণ এবং অ্যাক্সেস করতে পারবেন। -
firebase_ui_authপ্যাকেজ : এই প্যাকেজটি অথেন্টিকেশন সেটআপ করা অনেক দ্রুত করে তোলে। এটি ব্যবহারের জন্য তৈরি উইজেট (যেমন আগে থেকে তৈরি লগইন স্ক্রিন) সরবরাহ করে, ফলে আপনাকে সবকিছু গোড়া থেকে তৈরি করতে হয় না। -
providerপ্যাকেজ : স্টেট ম্যানেজমেন্টের জন্য এটি একটি জনপ্রিয় বিকল্প। এটি আপনার অ্যাপকে বিভিন্ন তথ্য (যেমন কে লগ ইন করেছে) ট্র্যাক করতে এবং প্রয়োজনীয় সমস্ত স্ক্রিনে সেই ডেটা উপলব্ধ করতে সাহায্য করে।
আপনি প্রয়োজনীয় প্যাকেজগুলো যোগ করেছেন, কিন্তু Firebase যথাযথভাবে ব্যবহার করার জন্য আপনাকে iOS, Android, macOS, এবং Web runner প্রজেক্টগুলোও কনফিগার করতে হবে। এছাড়াও আপনি provider প্যাকেজটি ব্যবহার করেন, যা বিজনেস লজিককে ডিসপ্লে লজিক থেকে আলাদা করতে সক্ষম করে।
FlutterFire CLI ইনস্টল করুন
FlutterFire CLI, অন্তর্নিহিত Firebase CLI-এর উপর নির্ভরশীল।
- যদি এখনও তা না করে থাকেন, তাহলে আপনার মেশিনে Firebase CLI ইনস্টল করুন।
- FlutterFire CLI ইনস্টল করুন:
$ dart pub global activate flutterfire_cli
একবার ইনস্টল হয়ে গেলে, flutterfire কমান্ডটি বিশ্বব্যাপী উপলব্ধ হয়।
আপনার অ্যাপগুলি কনফিগার করুন
একটি নির্দিষ্ট প্ল্যাটফর্মের সমস্ত কনফিগারেশন তৈরি করার জন্য CLI আপনার Firebase প্রজেক্ট এবং নির্বাচিত প্রজেক্ট অ্যাপগুলো থেকে তথ্য সংগ্রহ করে।
আপনার অ্যাপের রুটে ( flutter-codelabs/firebase-get-to-know-flutter/step_02 ), configure কমান্ডটি চালান:
$ flutterfire configure
কনফিগারেশন কমান্ডটি নিম্নলিখিত প্রক্রিয়াগুলো সম্পন্ন করে:
-
.firebasercফাইল থেকে অথবা ফায়ারবেস কনসোল থেকে একটি ফায়ারবেস প্রজেক্ট নির্বাচন করুন। - কনফিগারেশনের জন্য প্ল্যাটফর্ম নির্ধারণ করুন, যেমন অ্যান্ড্রয়েড, আইওএস, ম্যাকওএস এবং ওয়েব।
- যে Firebase অ্যাপগুলো থেকে কনফিগারেশন সংগ্রহ করতে হবে, সেগুলো শনাক্ত করুন। ডিফল্টরূপে, CLI আপনার বর্তমান প্রজেক্ট কনফিগারেশনের উপর ভিত্তি করে Firebase অ্যাপগুলোকে স্বয়ংক্রিয়ভাবে মেলানোর চেষ্টা করে।
- আপনার প্রজেক্টে একটি
firebase_options.dartফাইল তৈরি করুন।
ম্যাকওএস কনফিগার করুন
ম্যাকওএস-এ ফ্লাটার সম্পূর্ণ স্যান্ডবক্সড অ্যাপ তৈরি করে। যেহেতু এই অ্যাপটি ফায়ারবেস সার্ভারগুলোর সাথে যোগাযোগের জন্য নেটওয়ার্ককে সংযুক্ত করে, তাই আপনাকে নেটওয়ার্ক ক্লায়েন্ট প্রিভিলেজ দিয়ে আপনার অ্যাপটি কনফিগার করতে হবে।
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>
আরও তথ্যের জন্য, ফ্লাটারের ডেস্কটপ সাপোর্ট দেখুন।
৫. RSVP কার্যকারিতা যোগ করুন
এখন যেহেতু আপনি অ্যাপটিতে Firebase যোগ করেছেন, আপনি একটি RSVP বাটন তৈরি করতে পারেন যা অথেনটিকেশনের মাধ্যমে ব্যবহারকারীদের রেজিস্টার করবে। Android native, iOS native, এবং Web-এর জন্য আগে থেকে তৈরি FirebaseUI Auth প্যাকেজ রয়েছে, কিন্তু Flutter-এর জন্য আপনাকে এই সক্ষমতাটি বিল্ড করতে হবে।
আপনি পূর্বে যে প্রজেক্টটি সংগ্রহ করেছিলেন, তাতে এমন কিছু উইজেট অন্তর্ভুক্ত ছিল যা অথেনটিকেশন ফ্লো-এর বেশিরভাগ অংশের ইউজার ইন্টারফেস বাস্তবায়ন করে। আপনি অ্যাপের সাথে অথেনটিকেশন ইন্টিগ্রেট করার জন্য বিজনেস লজিক বাস্তবায়ন করবেন।
Provider প্যাকেজের সাথে ব্যবসায়িক যুক্তি যোগ করুন
অ্যাপের ফ্লাটার উইজেট ট্রি জুড়ে একটি কেন্দ্রীভূত অ্যাপ স্টেট অবজেক্ট উপলব্ধ করতে provider প্যাকেজটি ব্যবহার করুন:
-
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-গুলো ব্যবহার করেন, যা আপনার অ্যাপে দ্রুত লগইন স্ক্রিন বুটস্ট্র্যাপ করার একটি চমৎকার উপায়।
প্রমাণীকরণ প্রবাহকে একীভূত করুন
-
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';
- অ্যাপ ইনিশিয়ালাইজেশনের সাথে অ্যাপের স্টেট সংযুক্ত করুন এবং তারপরে
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 প্যাকেজকে জানিয়ে দেয় কখন নির্ভরশীল উইজেটগুলো পুনরায় প্রদর্শন করতে হবে।
- একটি
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,
),
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
textTheme: GoogleFonts.robotoTextTheme(
Theme.of(context).textTheme,
),
visualDensity: VisualDensity.adaptivePlatformDensity
),
routerConfig: _router, // new
);
}
}
অথেনটিকেশন ফ্লো-এর নতুন অবস্থার উপর ভিত্তি করে প্রতিটি স্ক্রিনের সাথে ভিন্ন ধরনের অ্যাকশন যুক্ত থাকে। অথেনটিকেশনের বেশিরভাগ অবস্থা পরিবর্তনের পরে, আপনি আপনার পছন্দের স্ক্রিনে ফিরে যেতে পারেন, সেটা হোম স্ক্রিন হোক বা প্রোফাইলের মতো অন্য কোনো স্ক্রিন।
-
HomePageক্লাসের build মেথডে,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 প্যাকেজ ব্যবহার করার প্রচলিত উপায় হলো Consumer উইজেট। AuthFunc উইজেটটি হলো সেই সম্পূরক উইজেট যা আপনি পরীক্ষা করেন।
প্রমাণীকরণ প্রবাহ পরীক্ষা করতে অ্যাপটি চালান।

- অ্যাপে,
SignInScreenচালু করতে RSVP বাটনটিতে ট্যাপ করুন।

- একটি ইমেল ঠিকানা লিখুন। আপনি যদি আগে থেকেই নিবন্ধিত থাকেন, তাহলে সিস্টেম আপনাকে একটি পাসওয়ার্ড লিখতে বলবে। অন্যথায়, সিস্টেম আপনাকে নিবন্ধন ফর্মটি পূরণ করতে বলবে।

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

৬. ফায়ারস্টোরে বার্তা লিখুন
ব্যবহারকারীরা আসছেন জেনে ভালো লাগছে, কিন্তু অ্যাপের মধ্যে অতিথিদের করার জন্য আপনাকে আরও কিছু দিতে হবে। কেমন হয় যদি তারা একটি গেস্টবুকে বার্তা রেখে যেতে পারত? সেখানে তারা জানাতে পারবে কেন তারা আসতে আগ্রহী অথবা কার সাথে দেখা করার আশা করছে।
অ্যাপে ব্যবহারকারীদের লেখা চ্যাট বার্তাগুলো সংরক্ষণ করতে ফায়ারস্টোর ব্যবহার করা হয়।
ডেটা মডেল
ফায়ারস্টোর একটি NoSQL ডাটাবেস, এবং এতে সংরক্ষিত ডেটা কালেকশন, ডকুমেন্ট, ফিল্ড ও সাব-কালেকশনে বিভক্ত থাকে। আপনি চ্যাটের প্রতিটি মেসেজকে একটি guestbook কালেকশনে ডকুমেন্ট হিসেবে সংরক্ষণ করেন, যা একটি টপ-লেভেল কালেকশন।

ফায়ারস্টোরে বার্তা যোগ করুন
এই অংশে, ব্যবহারকারীদের ডাটাবেসে বার্তা লেখার কার্যকারিতা যোগ করতে হবে। প্রথমে, একটি ফর্ম ফিল্ড এবং একটি সেন্ড বাটন যোগ করুন, এবং তারপর এই উপাদানগুলোকে ডাটাবেসের সাথে সংযুক্ত করার কোড যোগ করুন।
-
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 ব্যবহার করে ফর্মের পেছনের স্টেট অ্যাক্সেস করেন। Key এবং সেগুলো কীভাবে ব্যবহার করতে হয় সে সম্পর্কে আরও তথ্যের জন্য, “When to Use Keys” দেখুন।
উইজেটগুলো যেভাবে সাজানো আছে, সেদিকেও লক্ষ্য করুন; এখানে একটি Row এর মধ্যে একটি TextFormField এবং একটি StyledButton রয়েছে, যার ভেতরে আবার একটি Row আছে। আরও লক্ষ্য করুন যে TextFormField একটি Expanded উইজেটের মধ্যে মোড়ানো আছে, যা TextFormField Row-এর যেকোনো অতিরিক্ত জায়গা পূরণ করতে বাধ্য করে। এটি কেন প্রয়োজন, তা আরও ভালোভাবে বুঝতে “Understanding constraints” দেখুন।
এখন যেহেতু আপনার কাছে এমন একটি উইজেট আছে যা ব্যবহারকারীকে গেস্ট বুকে যোগ করার জন্য কিছু টেক্সট প্রবেশ করাতে সক্ষম করে, আপনাকে এটি স্ক্রিনে আনতে হবে।
-
HomePageএর মূল অংশ সম্পাদনা করেListViewএর children-গুলোর শেষে নিম্নলিখিত দুটি লাইন যোগ করুন:
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)),
যদিও এটি উইজেটটি প্রদর্শনের জন্য যথেষ্ট, তবে কোনো দরকারি কাজ করার জন্য এটি যথেষ্ট নয়। এটিকে কার্যকরী করতে আপনি শীঘ্রই এই কোডটি আপডেট করবেন।
অ্যাপ প্রিভিউ
|
|
|
|
যখন কোনো ব্যবহারকারী 'SEND' বোতামে ক্লিক করেন, তখন নিম্নলিখিত কোড স্নিপেটটি সক্রিয় হয়। এটি মেসেজ ইনপুট ফিল্ডের বিষয়বস্তু ডাটাবেসের 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) আছে যেখানে ব্যবহারকারী গেস্ট বুকে যোগ করার জন্য টেক্সট লিখতে পারেন এবং ফায়ারস্টোরে এন্ট্রিটি যোগ করার কোডও আপনার কাছে আছে। এখন আপনাকে শুধু এই দুটিকে সংযুক্ত করতে হবে।
-
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({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'),
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-তে কেউ মেসেজ প্রবেশ করালে আপনি তার প্রতিক্রিয়া জানাতে এবং সেটি ডেটাবেসে প্রকাশ করতে পারবেন। পরবর্তী অংশে, আপনি পরীক্ষা করে দেখবেন যে যোগ করা মেসেজগুলো ডেটাবেসে প্রকাশিত হয়েছে কি না।
বার্তা পাঠানোর পরীক্ষা
- প্রয়োজনে অ্যাপটিতে সাইন ইন করুন।
- একটি বার্তা লিখুন, যেমন
Hey there!’, এবং তারপর ‘প্রেরণ করুন’ বোতামে চাপ দিন।
এই কাজটি আপনার ফায়ারস্টোর ডেটাবেসে বার্তাটি লিখে দেয়। তবে, আপনি আপনার আসল ফ্লাটার অ্যাপে বার্তাটি দেখতে পাবেন না, কারণ আপনাকে এখনও ডেটা পুনরুদ্ধারের ব্যবস্থা করতে হবে, যা আপনি পরবর্তী ধাপে করবেন। কিন্তু, ফায়ারবেস কনসোলের ডেটাবেস ড্যাশবোর্ডে , আপনি guestbook কালেকশনে আপনার যোগ করা বার্তাটি দেখতে পাবেন। আপনি যত বেশি বার্তা পাঠাবেন, আপনার guestbook কালেকশনে তত বেশি ডকুমেন্ট যুক্ত হবে। উদাহরণস্বরূপ, নিচের কোড স্নিপেটটি দেখুন:

৭. বার্তাগুলো পড়ুন
এটা খুবই ভালো যে অতিথিরা ডাটাবেসে বার্তা লিখতে পারেন, কিন্তু তাঁরা এখনও অ্যাপে সেগুলো দেখতে পান না। এখন এটা ঠিক করার সময় এসেছে!
বার্তা সিঙ্ক্রোনাইজ করুন
মেসেজ দেখানোর জন্য, আপনাকে এমন লিসেনার যোগ করতে হবে যা ডেটা পরিবর্তনের সময় ট্রিগার হয় এবং তারপর নতুন মেসেজ দেখানোর জন্য একটি UI এলিমেন্ট তৈরি করতে হবে। আপনি অ্যাপ স্টেটে এমন কোড যোগ করবেন যা অ্যাপ থেকে নতুন যোগ হওয়া মেসেজগুলো শোনে।
-
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;
}
-
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
-
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.
-
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;
// Add from here...
_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();
});
// ...to here.
} else {
_loggedIn = false;
// Add from here...
_guestBookMessages = [];
_guestBookSubscription?.cancel();
// to here.
}
notifyListeners();
});
}
এই অংশটি গুরুত্বপূর্ণ, কারণ এখানেই আপনি guestbook কালেকশনের উপর একটি কোয়েরি তৈরি করেন এবং এই কালেকশনে সাবস্ক্রাইব ও আনসাবস্ক্রাইব করার বিষয়টি পরিচালনা করেন। আপনি স্ট্রিমটি শোনেন, যেখানে আপনি guestbook কালেকশনের মেসেজগুলোর একটি লোকাল ক্যাশে পুনর্গঠন করেন এবং এই সাবস্ক্রিপশনটির একটি রেফারেন্সও সংরক্ষণ করেন, যাতে আপনি পরে এটি থেকে আনসাবস্ক্রাইব করতে পারেন। এখানে অনেক কিছু ঘটে, তাই কী ঘটছে তা পরীক্ষা করে একটি পরিষ্কার ধারণা পেতে আপনার এটি একটি ডিবাগারে অন্বেষণ করা উচিত। আরও তথ্যের জন্য, “ফায়ারস্টোর দিয়ে রিয়েলটাইম আপডেট পান” দেখুন।
-
lib/guest_book.dartফাইলে নিম্নলিখিত ইম্পোর্টটি যোগ করুন:
import 'guest_book_message.dart';
-
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
State<GuestBook> createState() => _GuestBookState();
}
- এই কনফিগারেশনটি প্রকাশ করার জন্য
_GuestBookStateএরbuildমেথডটি নিম্নরূপভাবে পরিবর্তন করুন:
lib/guest_book.dart
class _GuestBookState extends State<GuestBook> {
final _formKey = GlobalKey<FormState>(debugLabel: '_GuestBookState');
final _controller = TextEditingController();
@override
Widget build(BuildContext context) {
// Modify from here...
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: [
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 এর চাইল্ডগুলোর শেষে একটি কালেকশন যোগ করেন।
- নতুন
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
),
],
],
),
),
পরীক্ষার বার্তা সিঙ্ক্রোনাইজেশন
ফায়ারস্টোর ডাটাবেসে সাবস্ক্রাইব করা ক্লায়েন্টদের সাথে স্বয়ংক্রিয়ভাবে এবং তাৎক্ষণিকভাবে ডেটা সিঙ্ক্রোনাইজ করে।
পরীক্ষার বার্তা সিঙ্ক্রোনাইজেশন:
- অ্যাপটিতে, ডাটাবেস থেকে আপনার আগে তৈরি করা মেসেজগুলো খুঁজুন।
- নতুন বার্তা লিখুন। সেগুলো সঙ্গে সঙ্গে প্রদর্শিত হবে।
- আপনার কর্মক্ষেত্রটি একাধিক উইন্ডো বা ট্যাবে খুলুন। বার্তাগুলো উইন্ডো এবং ট্যাবজুড়ে রিয়েল টাইমে সিঙ্ক হয়।
- ঐচ্ছিক: Firebase কনসোলের ডেটাবেস মেনুতে, ম্যানুয়ালি মেসেজ মুছুন, পরিবর্তন করুন বা নতুন মেসেজ যোগ করুন। সমস্ত পরিবর্তন UI-তে দেখা যাবে।
অভিনন্দন! আপনি আপনার অ্যাপে ফায়ারস্টোর ডকুমেন্ট পড়তে পারছেন!
অ্যাপ প্রিভিউ
|
|
|
|
৮. প্রাথমিক নিরাপত্তা নিয়মাবলী স্থাপন করুন।
আপনি প্রাথমিকভাবে ফায়ারস্টোরকে টেস্ট মোড ব্যবহার করার জন্য সেট আপ করেন, যার মানে হলো আপনার ডাটাবেসটি রিড এবং রাইটের জন্য উন্মুক্ত থাকে। তবে, আপনার শুধুমাত্র ডেভেলপমেন্টের প্রাথমিক পর্যায়েই টেস্ট মোড ব্যবহার করা উচিত। একটি উত্তম অনুশীলন হিসেবে, আপনার অ্যাপ ডেভেলপ করার সময়ই ডাটাবেসের জন্য সিকিউরিটি রুলস সেট আপ করা উচিত। নিরাপত্তা আপনার অ্যাপের গঠন এবং আচরণের জন্য অবিচ্ছেদ্য।
ফায়ারবেস সিকিউরিটি রুলস আপনাকে আপনার ডাটাবেসের ডকুমেন্ট এবং কালেকশনগুলিতে অ্যাক্সেস নিয়ন্ত্রণ করতে দেয়। এর নমনীয় রুল সিনট্যাক্স আপনাকে এমন নিয়ম তৈরি করতে দেয় যা পুরো ডাটাবেসে সমস্ত রাইট অপারেশন থেকে শুরু করে একটি নির্দিষ্ট ডকুমেন্টের অপারেশন পর্যন্ত যেকোনো কিছুর সাথে মিল খুঁজে বের করতে পারে।
প্রাথমিক নিরাপত্তা নিয়মাবলী সেট আপ করুন:
- Firebase কনসোলের Develop মেনুতে, Database > Rules-এ ক্লিক করুন। আপনি নিম্নলিখিত ডিফল্ট নিরাপত্তা নিয়মগুলি এবং নিয়মগুলি পাবলিক হওয়ার বিষয়ে একটি সতর্কবার্তা দেখতে পাবেন:

- অ্যাপটি যে কালেকশনগুলিতে ডেটা লেখে, সেগুলি শনাক্ত করুন:
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.
}
}
যেহেতু আপনি প্রতিটি গেস্টবুক ডকুমেন্টে একটি ফিল্ড হিসেবে অথেনটিকেশন ইউআইডি ব্যবহার করেছেন, তাই আপনি অথেনটিকেশন ইউআইডিটি সংগ্রহ করে যাচাই করতে পারবেন যে, ডকুমেন্টটিতে লেখার চেষ্টাকারী প্রত্যেকের একটি মিলে যাওয়া অথেনটিকেশন ইউআইডি রয়েছে।
- আপনার নিয়ম সেটে পঠন এবং লিখন নিয়মগুলো যোগ করুন:
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;
}
}
}
এখন, শুধুমাত্র সাইন-ইন করা ব্যবহারকারীরাই গেস্ট বুকের বার্তা পড়তে পারবেন, কিন্তু শুধুমাত্র বার্তার লেখকই বার্তাটি সম্পাদনা করতে পারবেন।
- ডকুমেন্টে সমস্ত প্রত্যাশিত ফিল্ড উপস্থিত আছে কিনা তা নিশ্চিত করতে ডেটা ভ্যালিডেশন যোগ করুন:
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;
}
}
}
৯. অতিরিক্ত ধাপ: যা শিখেছেন তা অনুশীলন করুন।
অংশগ্রহণকারীর RSVP অবস্থা নথিভুক্ত করুন।
বর্তমানে, আপনার অ্যাপটি শুধুমাত্র ইভেন্টটিতে আগ্রহী ব্যক্তিদেরই চ্যাট করার সুযোগ দেয়। এছাড়াও, কেউ আসছে কি না, তা জানার একমাত্র উপায় হলো যখন তারা চ্যাটে তা জানায়।
এই ধাপে, আপনি সবকিছু গুছিয়ে নেন এবং কতজন আসছেন তা সবাইকে জানিয়ে দেন। আপনি অ্যাপের স্টেটে কয়েকটি বৈশিষ্ট্য যোগ করেন। প্রথমটি হলো, লগ-ইন করা কোনো ব্যবহারকারী অনুষ্ঠানে যোগ দেবেন কি না, তা জানানোর সুযোগ। দ্বিতীয়টি হলো, কতজন যোগ দিচ্ছেন তার একটি কাউন্টার।
-
lib/app_state.dartফাইলেরApplicationStateএর accessors সেকশনে নিম্নলিখিত লাইনগুলো যোগ করুন, যাতে 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});
}
}
-
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();
});
}
এই কোডটি অংশগ্রহণকারীদের সংখ্যা নির্ধারণ করার জন্য একটি সর্বদা-সাবস্ক্রাইবড কোয়েরি এবং ব্যবহারকারী অংশগ্রহণ করছেন কিনা তা নির্ধারণ করার জন্য দ্বিতীয় একটি কোয়েরি যোগ করে, যা শুধুমাত্র ব্যবহারকারী লগ ইন থাকা অবস্থায় সক্রিয় থাকে।
-
lib/app_state.dartফাইলের শীর্ষে নিম্নলিখিত এনুমারেশনটি যোগ করুন।
lib/app_state.dart
enum Attending { yes, no, unknown }
-
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'),
),
],
),
);
}
}
}
এটি একটি অনির্দিষ্ট অবস্থায় শুরু হয়, যেখানে 'হ্যাঁ' বা ' না' কোনোটিই নির্বাচিত থাকে না। ব্যবহারকারী একবার অংশগ্রহণ করবেন কিনা তা নির্বাচন করলে, সেই বিকল্পটি একটি ভরাট বোতামের মাধ্যমে হাইলাইট করে দেখানো হয় এবং অন্য বিকল্পটি একটি সমতল রেন্ডারিং হিসেবে অদৃশ্য হয়ে যায়।
-
HomePageএরbuild()মেথডটি আপডেট করুন যাতেYesNoSelectionএর সুবিধা নেওয়া যায়, লগ-ইন করা ব্যবহারকারী ইভেন্টে অংশগ্রহণ করছেন কিনা তা মনোনীত করতে পারেন, এবং ইভেন্টের অংশগ্রহণকারীদের সংখ্যা প্রদর্শন করা যায়:
lib/home_page.dart
import 'yes_no_selection.dart'; // new
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 কালেকশনে সংযোজনের অনুমতি দেওয়ার জন্য আপনাকে নিয়মগুলো আপডেট করতে হবে।
-
attendeesসংগ্রহ থেকে, ডকুমেন্টের নাম হিসেবে ব্যবহৃত অথেনটিকেশন ইউআইডি (Authorization UID) নিন এবং যাচাই করুন যে জমা প্রদানকারীরuidতার লেখা ডকুমেন্টের ইউআইডি-র (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;
}
}
}
এর ফলে উপস্থিতদের তালিকাটি সবাই পড়তে পারে, কারণ সেখানে কোনো ব্যক্তিগত তথ্য থাকে না, কিন্তু শুধুমাত্র নির্মাতাই এটি হালনাগাদ করতে পারেন।
- ডকুমেন্টে সমস্ত প্রত্যাশিত ফিল্ড উপস্থিত আছে কিনা তা নিশ্চিত করতে ডেটা ভ্যালিডেশন যোগ করুন:
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;
}
}
}
- ঐচ্ছিক: অ্যাপের মধ্যে, Firebase কনসোলের Firestore ড্যাশবোর্ডে ফলাফল দেখতে বাটনগুলোতে ক্লিক করুন।
অ্যাপ প্রিভিউ
|
|
|
|
১০. অভিনন্দন!
আপনি ফায়ারবেস ব্যবহার করে একটি ইন্টারেক্টিভ, রিয়েল-টাইম ওয়েব অ্যাপ তৈরি করেছেন!















