Skip to content

Commit acc6630

Browse files
authored
Last minute changes (flutter#1126)
1 parent 2db36b4 commit acc6630

4 files changed

Lines changed: 101 additions & 251 deletions

File tree

firebase-get-to-know-flutter/step_09/lib/main.dart

Lines changed: 73 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class App extends StatelessWidget {
5050
}
5151
if (state is UserCreated) {
5252
user.updateDisplayName(user.email!.split('@')[0]);
53+
user.sendEmailVerification();
5354
}
5455
if (!user.emailVerified) {
5556
user.sendEmailVerification();
@@ -74,15 +75,29 @@ class App extends StatelessWidget {
7475
);
7576
}),
7677
'/profile': ((context) {
77-
return ProfileScreen(
78-
providers: const [],
79-
actions: [
80-
SignedOutAction(
81-
((context) {
82-
Navigator.of(context).popUntil(ModalRoute.withName('/home'));
83-
}),
84-
),
85-
],
78+
return Consumer<ApplicationState>(
79+
builder: (context, appState, _) => ProfileScreen(
80+
key: ValueKey(appState.emailVerified),
81+
providers: const [],
82+
actions: [
83+
SignedOutAction(
84+
((context) {
85+
Navigator.of(context)
86+
.popUntil(ModalRoute.withName('/home'));
87+
}),
88+
),
89+
],
90+
children: [
91+
Visibility(
92+
visible: !appState.emailVerified,
93+
child: OutlinedButton(
94+
child: const Text('Recheck Verification State'),
95+
onPressed: () {
96+
appState.refreshLoggedInUser();
97+
},
98+
))
99+
],
100+
),
86101
);
87102
})
88103
},
@@ -114,14 +129,19 @@ class HomePage extends StatelessWidget {
114129
children: <Widget>[
115130
Image.asset('assets/codelab.png'),
116131
const SizedBox(height: 8),
117-
const IconAndDetail(Icons.calendar_today, 'October 30'),
132+
Consumer<ApplicationState>(
133+
builder: (context, appState, _) =>
134+
IconAndDetail(Icons.calendar_today, appState.eventDate),
135+
),
118136
const IconAndDetail(Icons.location_city, 'San Francisco'),
119137
Consumer<ApplicationState>(
120138
builder: (context, appState, _) => AuthFunc(
121-
loggedIn: appState.loggedIn,
122-
signOut: () {
123-
FirebaseAuth.instance.signOut();
124-
}),
139+
loggedIn: appState.loggedIn,
140+
signOut: () {
141+
FirebaseAuth.instance.signOut();
142+
},
143+
enableFreeSwag: appState.enableFreeSwag,
144+
),
125145
),
126146
const Divider(
127147
height: 8,
@@ -131,8 +151,10 @@ class HomePage extends StatelessWidget {
131151
color: Colors.grey,
132152
),
133153
const Header("What we'll be doing"),
134-
const Paragraph(
135-
'Join us for a day full of Firebase Workshops and Pizza!',
154+
Consumer<ApplicationState>(
155+
builder: (context, appState, _) => Paragraph(
156+
appState.callToAction,
157+
),
136158
),
137159
Consumer<ApplicationState>(
138160
builder: (context, appState, _) => Column(
@@ -175,13 +197,36 @@ class ApplicationState extends ChangeNotifier {
175197
bool _loggedIn = false;
176198
bool get loggedIn => _loggedIn;
177199

200+
bool _emailVerified = false;
201+
bool get emailVerified => _emailVerified;
202+
178203
StreamSubscription<QuerySnapshot>? _guestBookSubscription;
179204
List<GuestBookMessage> _guestBookMessages = [];
180205
List<GuestBookMessage> get guestBookMessages => _guestBookMessages;
181206

182207
int _attendees = 0;
183208
int get attendees => _attendees;
184209

210+
static Map<String, dynamic> defaultValues = <String, dynamic>{
211+
'event_date': 'October 18, 2022',
212+
'enable_free_swag': false,
213+
'call_to_action': 'Join us for a day full of Firebase Workshops and Pizza!',
214+
};
215+
216+
// ignoring lints on these fields since we are modifying them in a different
217+
// part of the codelab
218+
// ignore: prefer_final_fields
219+
bool _enableFreeSwag = defaultValues['enable_free_swag'] as bool;
220+
bool get enableFreeSwag => _enableFreeSwag;
221+
222+
// ignore: prefer_final_fields
223+
String _eventDate = defaultValues['event_date'] as String;
224+
String get eventDate => _eventDate;
225+
226+
// ignore: prefer_final_fields
227+
String _callToAction = defaultValues['call_to_action'] as String;
228+
String get callToAction => _callToAction;
229+
185230
Attending _attending = Attending.unknown;
186231
StreamSubscription<DocumentSnapshot>? _attendingSubscription;
187232
Attending get attending => _attending;
@@ -216,6 +261,7 @@ class ApplicationState extends ChangeNotifier {
216261
FirebaseAuth.instance.userChanges().listen((user) {
217262
if (user != null) {
218263
_loggedIn = true;
264+
_emailVerified = user.emailVerified;
219265
_guestBookSubscription = FirebaseFirestore.instance
220266
.collection('guestbook')
221267
.orderBy('timestamp', descending: true)
@@ -250,6 +296,7 @@ class ApplicationState extends ChangeNotifier {
250296
});
251297
} else {
252298
_loggedIn = false;
299+
_emailVerified = false;
253300
_guestBookMessages = [];
254301
_guestBookSubscription?.cancel();
255302
_attendingSubscription?.cancel();
@@ -258,6 +305,16 @@ class ApplicationState extends ChangeNotifier {
258305
});
259306
}
260307

308+
Future<void> refreshLoggedInUser() async {
309+
final currentUser = FirebaseAuth.instance.currentUser;
310+
311+
if (currentUser == null) {
312+
return;
313+
}
314+
315+
await currentUser.reload();
316+
}
317+
261318
Future<DocumentReference> addMessageToGuestBook(String message) {
262319
if (!_loggedIn) {
263320
throw Exception('Must be logged in');

firebase-get-to-know-flutter/step_09/lib/src/authentication.dart

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ class AuthFunc extends StatelessWidget {
77
super.key,
88
required this.loggedIn,
99
required this.signOut,
10+
this.enableFreeSwag = false,
1011
});
1112

1213
final bool loggedIn;
1314
final void Function() signOut;
15+
final bool enableFreeSwag;
1416

1517
@override
1618
Widget build(BuildContext context) {
@@ -35,7 +37,17 @@ class AuthFunc extends StatelessWidget {
3537
Navigator.of(context).pushNamed('/profile');
3638
},
3739
child: const Text('Profile')),
38-
))
40+
)),
41+
Visibility(
42+
visible: enableFreeSwag,
43+
child: Padding(
44+
padding: const EdgeInsets.only(left: 24, bottom: 8),
45+
child: StyledButton(
46+
onPressed: () {
47+
throw Exception('free swag unimplemented');
48+
},
49+
child: const Text('Free swag!')),
50+
)),
3951
],
4052
);
4153
}

firebase-get-to-know-flutter/supplemental/part_01/README.md

Lines changed: 14 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ Before we write any code, we need to configure our applications for Firebase MFA
1414

1515
### Android
1616

17-
For Android, you will want to register your SHA-256 certificate fingerprint in the console. If you are working with the default android signing key, you can find that fingerprint through the keytool command using :
17+
For Android, you will want to register your SHA-256 certificate fingerprint in the console. If you are working with the default android signing key, you can find that fingerprint through the gradlew command using :
1818

1919
```shell
20-
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
20+
cd android
21+
./gradlew signingReport
2122
```
2223

2324
More information about signing keys can be found in this resource:
@@ -36,87 +37,36 @@ Once you have this value, you will want to open your project in XCode and go to
3637

3738
## Code
3839

39-
The first thing that we would want to do is to update the `ApplicationState` class at the bottom of the `main.dart` file. In this class we want to add a check on whether the user has verified their email address as users cannot start to enroll in MFA until they have a verified email address. The changes we would want to make would look like:
40-
41-
```dart
42-
bool _loggedIn = false;
43-
bool get loggedIn => _loggedIn;
44-
45-
// Add from here
46-
bool _emailVerified = false;
47-
bool get emailVerified => _emailVerified;
48-
// To here
49-
```
50-
51-
and
52-
53-
```dart
54-
FirebaseAuth.instance.userChanges().listen((user) {
55-
if (user != null) {
56-
_loggedIn = true;
57-
// add the following line
58-
_emailVerified = user.emailVerified;
59-
```
60-
61-
The problem though is that this check only runs after a user has logged in, and does not run when a user may do things like check the profile screen or do an out of band verification of their email address. To reload a user after they may have done an out of band email verification, we would want to add the following method to the `ApplicationState` class.
62-
63-
```dart
64-
// Add from here
65-
Future<void> refreshLoggedInUser() async {
66-
if (!loggedIn) {
67-
return;
68-
}
69-
await FirebaseAuth.instance.currentUser!.reload();
70-
}
71-
// to here
72-
73-
Future<DocumentReference> addMessageToGuestBook(String message) {
74-
//...
75-
```
76-
77-
Now that we are able to check the verified email state, we would want to ensure that the user is able to get a verification email from Firebase. To add in an automatic verification email to be sent on user creation, add the following to the sign-in route of your applicaiton.
78-
79-
```dart
80-
if (user == null) {
81-
return;
82-
}
83-
if (state is UserCreated) {
84-
user.updateDisplayName(user.email!.split('@')[0]);
85-
// Add the following line
86-
user.sendEmailVerification();
87-
}
88-
```
89-
9040
Next, we would want to provide a way for the user to enroll in MFA after they have verified their email. They can visit their profile page which should contain information about their user account. In this page, they should know whether or not their email was verified and if their email was verified, show an enrollment option for MFA. This will require us to consume our application state and check whether or not the email was verified and if it was, show the MFA enrollment option. If it was not verified, a yellow banner will be shown instead. We add in an out of band verification button for verification of the email verification since to automatically redirect back to the application, we would need to integrate deep linking. We use a key to determine whether or not the state of this widget needs to be updated and redrawn.
9141

9242
```dart
9343
'/profile': ((context) {
94-
//modify from here
9544
return Consumer<ApplicationState>(
9645
builder: (context, appState, _) => ProfileScreen(
9746
key: ValueKey(appState.emailVerified),
9847
providers: const [],
48+
// add the following line
9949
showMFATile: appState.emailVerified,
50+
// finish adding
51+
actions: [
52+
SignedOutAction(
53+
((context) {
54+
Navigator.of(context)
55+
.popUntil(ModalRoute.withName('/home'));
56+
}),
57+
),
58+
],
10059
children: [
10160
Visibility(
10261
visible: !appState.emailVerified,
10362
child: OutlinedButton(
10463
onPressed: () {
10564
appState.refreshLoggedInUser();
10665
},
107-
child: Text("Re-check email verification status"),
66+
child: Text("Recheck email verification status"),
10867
),
10968
),
11069
],
111-
// to here
112-
actions: [
113-
SignedOutAction(
114-
((context) {
115-
Navigator.of(context)
116-
.popUntil(ModalRoute.withName('/home'));
117-
}),
118-
),
119-
],
12070
),
12171
);
12272
})

0 commit comments

Comments
 (0)