我很喜歡這篇 CodeLab,我自己認為,如果這篇的內容看得懂那 Provider
基本上都會了。
如果想要看這篇的成品什麼樣子,歡迎去 官方 CodeLab 看。
接續 【第十四天 - Flutter 官方 CodeLab Get-To-Know 活動報名教學(上)】,直接進入主題介紹方法。
在使用 Firebase 的時候都需要初始化。
await Firebase.initializeApp();
這邊是用來查看有幾個人參加報名的,不需要判斷有無登入,都需要有參與者的人數。
可以看到這裡,他去找尋 collection == attendees
並找尋底下的 attending 欄位 == true
,並進行即時監聽資料。可以看到這裡,他去找尋 collection == attendees
並找尋底下的 attending 欄位 == true
,並進行即時監聽資料。
FirebaseFirestore.instance
.collection('attendees')
.where('attending', isEqualTo: true)
.snapshots()
.listen((snapshot) {
_attendees = snapshot.docs.length;
notifyListeners();
});
這邊是先判斷使用者是否有登入
未登入
Subscription
collection == guestbook
,並且照著 timestamp 由大到小排序
,並讀取每一個 document 的資料
)FirebaseFirestore.instance.collection('attendees').doc(user.uid)
,是表示他要去取得 attendees
的資料,並且 doc 的 id == user.uid(現在使用者 的 uid)
。 // 監聽使用者使否有登入的資訊
FirebaseAuth.instance.userChanges().listen((user) {
// 更改後,使用者從無登入 -> 已經登入的狀態
if (user != null) {
_loginState = ApplicationLoginState.loggedIn;
// StreamSubscription 監聽資訊
_guestBookSubscription = FirebaseFirestore.instance
.collection('guestbook')
.orderBy('timestamp', descending: true)
.snapshots()
.listen((snapshot) {
// 先清空資料
_guestBookMessages = [];
snapshot.docs.forEach((document) {
_guestBookMessages.add(
GuestBookMessage(
name: document.data()['name'].toString(),
message: document.data()['text'].toString(),
),
);
});
// 資料變動完後, rebuild 畫面
notifyListeners();
});
// 監聽 attending 參加人數的資料
_attendingSubscription = FirebaseFirestore.instance
.collection('attendees')
.doc(user.uid)
.snapshots()
.listen((snapshot) {
if (snapshot.data() != null) {
if (snapshot['attending']==true) {
_attending = Attending.yes;
} else {
_attending = Attending.no;
}
} else {
_attending = Attending.unknown;
}
notifyListeners();
});
} else {
// 關閉監聽器
_loginState = ApplicationLoginState.loggedOut;
_guestBookMessages = [];
_guestBookSubscription?.cancel();
_attendingSubscription?.cancel(); // new
}
notifyListeners();
});
```
# 更新參與者狀況
這邊會去存入 `collection == attendees` 且 `document id == currentUser.uid`。
存入資料都必須像這樣,是一個 `map` 的型態。
```dart
/// 更新 firebase user 的參加狀態。
/// 這邊更新後會觸發 firebase 的 userChanges().listen,然後信行 attending 的更新
set attending(Attending attending) {
final userDoc = FirebaseFirestore.instance
.collection('attendees')
.doc(FirebaseAuth.instance.currentUser!.uid);
if (attending == Attending.yes) {
var map = {'attending': true};
userDoc.set(map);
} else {
var map = {'attending': false};
userDoc.set(map);
}
}
這邊會去存入 `collection == guestbook`,這邊沒有指定 `document` 的名稱,因此 `firebase` 會隨機產生。
存入資料都必須像這樣,是一個 map 的型態。
/// 更新 firebase message 的留言狀態。
/// 這邊更新後會觸發 firebase 的 userChanges().listen,然後信行 attending 的更新
Future<DocumentReference> addMessageToGuestBook(String message) {
if (_loginState != ApplicationLoginState.loggedIn) {
throw Exception('Must be logged in');
}
var map = {
'text': message,
'timestamp': DateTime.now().millisecondsSinceEpoch,
'name': FirebaseAuth.instance.currentUser!.displayName,
'userId': FirebaseAuth.instance.currentUser!.uid,
};
return FirebaseFirestore.instance.collection('guestbook').add(map);
}
他會返回可用於登錄給定的登錄方法列表,用戶(由其主要電子郵件地址標識)。當您支持多種身份驗證機制時,此方法很有用。如果找不到用戶,則返回一個空的 List
。如果電子郵件地址無效則拋出 FirebaseAuthException
不合規電郵。
FirebaseAuth.instance.fetchSignInMethodsForEmail(email)
提供 eamil 的登入方式
FirebaseAuth.instance.signInWithEmailAndPassword
註冊
FirebaseAuth.instance
.createUserWithEmailAndPassword(email: email, password: password);
FirebaseAuth.instance.signOut();
Cosumer
,他類似一個 View
的控制器,他有 Cosumer2
、Cosumer3
等等...,builder
裡面第一個參數是 contex
t,第二個則是 model(ApplicationProvider 的 model)
,第三個則是 child
。
Consumer4 的範例
Consumer4<changeNotifier1, changeNotifier2, changeNotifier3, changeNotifier4>(
builder: (context, changeNotifier1, changeNotifier2, changeNotifier3, changeNotifier4, child) {
// return your widget
}
)
這邊的話,累是一個 View
的中轉站,從 ApplicationProvider
取得現在登入的狀態,和方法,在 Consumer
中轉站傳遞給自定義的 Authentication
元件,讓邏輯和畫面分離。並使用 callBack
的方式,讓 ApplicationProvider
,Firebase 裡面的 exception
可以顯示在畫面上面。
Consumer<ApplicationProvider>(
builder: (context, appState, _) {
return Authentication(
email: appState.email,
loginState: appState.loginState,
startLoginFlow: appState.startLoginFlow,
// 把邏輯寫在 provider 裡面。然後當 Widget 裡面觸發資料後
verifyEmail: appState.verifyEmail,
signInWithEmailAndPassword: appState.signInWithEmailAndPassword,
cancelRegistration: appState.cancelRegistration,
registerAccount: appState.registerAccount,
signOut: appState.signOut,
)
;
}
),
這篇雖然很長,但是只要看懂 provider
、Authentication
元件、CallBack
,整篇大約就會一目瞭然。
初接觸 Firebase
的朋友,可能就要了解一下要怎麼連接 Firebase
,還有 FireStore
怎麼使用,collection
、document
、userID
、還有一些即時更新的 listener
,需要去熟悉他,希望大家可以在 Flutter 上有所成長~~