Skip to content

Commit ee85c33

Browse files
committed
Added: auth flow & upgraded flutter to v.1.5
1 parent 49d0b96 commit ee85c33

18 files changed

+390
-132
lines changed

Diff for: lib/actions/auth_actions.dart

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import 'package:flutter_todo_redux/models/user.dart';
2+
3+
class AuthenticateAction {
4+
AuthenticateAction({this.username, this.password});
5+
6+
final String username, password;
7+
8+
@override
9+
String toString() {
10+
return "AuthenticateAction {username: $username, password: $password}";
11+
}
12+
}
13+
14+
class UnAuthenticateAction {}
15+
16+
class HasAuthenticatedAction {}
17+
18+
class AuthenticateSuccessAction {}
19+
20+
class AuthenticateFailedAction {}
21+
22+
class LoadAuthenticationUserListAction {}
23+
24+
class AuthenticationUserListAction {
25+
AuthenticationUserListAction({this.userList});
26+
27+
final List<User> userList;
28+
29+
@override
30+
String toString() {
31+
return "AuthenticationUserListAction {userList: $userList}";
32+
}
33+
}

Diff for: lib/actions/index.dart

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export 'counter_actions.dart';
22
export 'todos_actions.dart';
33
export 'navigate_actions.dart';
4+
export 'auth_actions.dart';

Diff for: lib/containers/home/todo_list.dart

+8-3
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,14 @@ class TodoList extends StatelessWidget {
1515
children: vm.todos.map(
1616
(Todo todo) {
1717
return ListTile(
18-
leading: Icon(
19-
Icons.toys,
20-
color: todo.completed ? Colors.lightGreen : null,
18+
leading: IconButton(
19+
icon: Icon(
20+
Icons.toys,
21+
color: todo.completed ? Colors.lightGreen : null,
22+
),
23+
onPressed: () {
24+
vm.onCheckboxChanged(todo, !todo.completed);
25+
},
2126
),
2227
title: Text(todo.title),
2328
trailing: Switch(

Diff for: lib/containers/login/button_bar.dart

+72-63
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import 'package:flutter/material.dart';
2-
import 'package:flutter_todo_redux/pages/splash_screen_page.dart';
2+
import 'package:flutter_redux/flutter_redux.dart';
3+
import 'package:flutter_todo_redux/actions/index.dart';
4+
import 'package:flutter_todo_redux/models/app_state.dart';
5+
import 'package:flutter_todo_redux/models/user.dart';
6+
import 'package:redux/redux.dart';
37

48
class ButtonBarWidget extends StatefulWidget {
59
ButtonBarWidget(this.userCreds, this.setUserCreds);
@@ -12,83 +16,88 @@ class ButtonBarWidget extends StatefulWidget {
1216
}
1317

1418
class _ButtonBarWidgetState extends State<ButtonBarWidget> {
15-
Future _getUserList;
16-
1719
@override
1820
void initState() {
1921
super.initState();
2022
}
2123

2224
@override
2325
Widget build(BuildContext context) {
24-
return ButtonTheme.bar(
25-
child: ButtonBar(
26-
alignment: MainAxisAlignment.spaceBetween,
27-
children: <Widget>[
28-
UserList(context, widget.setUserCreds),
29-
FlatButton(
30-
child: const Text('Register'),
31-
onPressed: () {
32-
_navigateToSplashScreen(context);
33-
},
34-
),
35-
FlatButton(
36-
child: const Text('Login'),
37-
onPressed: () {
38-
_authenticateUser();
39-
},
26+
return StoreConnector(
27+
converter: _ViewModel.fromStore,
28+
builder: (BuildContext context, _ViewModel vm) => ButtonTheme.bar(
29+
child: ButtonBar(
30+
alignment: MainAxisAlignment.spaceBetween,
31+
children: <Widget>[
32+
UserList(context, widget.setUserCreds),
33+
FlatButton(
34+
child: const Text('Register'),
35+
onPressed: () {
36+
print('Register');
37+
},
38+
),
39+
FlatButton(
40+
child: const Text('Login'),
41+
onPressed: () {
42+
vm.onLoginPressed(
43+
username: widget.userCreds['username'],
44+
password: widget.userCreds['password'],
45+
);
46+
},
47+
),
48+
],
49+
),
4050
),
41-
],
42-
),
4351
);
4452
}
4553

4654
// ignore: non_constant_identifier_names
47-
Widget UserList(context, setUserCreds) => FutureBuilder(
48-
future: _getUserList,
49-
builder: (BuildContext context, AsyncSnapshot snapshot) {
50-
switch (snapshot.connectionState) {
51-
case ConnectionState.none:
52-
case ConnectionState.active:
53-
case ConnectionState.waiting:
54-
return Container(
55-
child: Center(
56-
child: CircularProgressIndicator(),
57-
),
55+
Widget UserList(context, setUserCreds) {
56+
return StoreConnector(
57+
converter: _ViewModel.fromStore,
58+
builder: (BuildContext context, _ViewModel vm) {
59+
return DropdownButton<String>(
60+
hint: Text('Choose a user'),
61+
items: vm.userList.map(
62+
(value) {
63+
return DropdownMenuItem<String>(
64+
value: value.id.toString(),
65+
child: Text(value.username),
5866
);
59-
case ConnectionState.done:
60-
final List userList = snapshot.data;
67+
},
68+
).toList(),
69+
onChanged: (newValue) {
70+
final user = vm.userList.firstWhere((item) {
71+
return item.id.toString() == newValue;
72+
});
73+
setUserCreds('username', user.username);
74+
setUserCreds('password', user.id);
75+
},
76+
);
77+
},
78+
);
79+
}
80+
}
6181

62-
return DropdownButton<String>(
63-
hint: Text('Choose a user'),
64-
items: userList.map(
65-
(value) {
66-
return DropdownMenuItem<String>(
67-
value: value.id.toString(),
68-
child: Text(value.username),
69-
);
70-
},
71-
).toList(),
72-
onChanged: (newValue) {
73-
final user = userList.firstWhere((item) {
74-
return item.id.toString() == newValue;
75-
});
76-
setUserCreds('username', user.username);
77-
setUserCreds('password', user.id);
78-
},
79-
);
80-
}
81-
},
82-
);
82+
class _ViewModel {
83+
final List<User> userList;
84+
final bool loading;
85+
final Function onLoginPressed;
8386

84-
void _navigateToSplashScreen(BuildContext context) {
85-
Navigator.pushNamed(context, SplashScreenPage.routeName);
86-
}
87+
_ViewModel({this.loading, this.userList, this.onLoginPressed});
8788

88-
void _authenticateUser() {
89-
// _loginScreenBloc.dispatch(AuthenticateUser(
90-
// username: widget.userCreds['username'],
91-
// password: widget.userCreds['password'],
92-
// ));
89+
static _ViewModel fromStore(Store<AppState> store) {
90+
return _ViewModel(
91+
userList: store.state.userList,
92+
loading: store.state.isLoading,
93+
onLoginPressed: ({username, password}) {
94+
store.dispatch(
95+
AuthenticateAction(
96+
username: username,
97+
password: password,
98+
),
99+
);
100+
},
101+
);
93102
}
94103
}

Diff for: lib/main.dart

+21-9
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import 'package:flutter/material.dart';
2-
import 'package:flutter_todo_redux/middlewares/index.dart';
2+
33
import 'package:redux/redux.dart';
44
import 'package:flutter_redux/flutter_redux.dart';
55
import 'package:redux_logging/redux_logging.dart';
66

77
import 'package:flutter_todo_redux/actions/index.dart';
88
import 'package:flutter_todo_redux/reducers/app_reducer.dart';
9+
import 'package:flutter_todo_redux/middlewares/index.dart';
910

1011
import 'package:flutter_todo_redux/models/app_state.dart';
1112

@@ -19,11 +20,12 @@ void main() {
1920
final store = Store<AppState>(
2021
appReducer,
2122
initialState: AppState(),
22-
middleware: createStoreTodosMiddleware()
23-
..addAll([
24-
createRouteMiddleware(navigatorKey: navigatorKey),
25-
LoggingMiddleware.printer()
26-
]),
23+
middleware: [
24+
...createStoreTodosMiddleware(),
25+
...createAuthMiddleware(),
26+
createRouteMiddleware(navigatorKey: navigatorKey),
27+
LoggingMiddleware.printer(),
28+
],
2729
);
2830

2931
runApp(TodoApp(store: store));
@@ -46,17 +48,27 @@ class TodoApp extends StatelessWidget {
4648
SplashScreenPage.routeName: (BuildContext context) {
4749
return SplashScreenPage(
4850
onInit: () {
49-
StoreProvider.of<AppState>(context).dispatch(LoadTodosAction());
51+
StoreProvider.of<AppState>(context)
52+
.dispatch(HasAuthenticatedAction());
5053
},
5154
);
5255
},
5356
HomePage.routeName: (BuildContext context) {
5457
return HomePage(
55-
title: 'home',
58+
title: 'Home',
59+
onInit: () {
60+
StoreProvider.of<AppState>(context).dispatch(LoadTodosAction());
61+
},
5662
);
5763
},
5864
LoginPage.routeName: (BuildContext context) {
59-
return LoginPage();
65+
return LoginPage(
66+
title: 'Login',
67+
onInit: () {
68+
StoreProvider.of<AppState>(context)
69+
.dispatch(LoadAuthenticationUserListAction());
70+
},
71+
);
6072
}
6173
},
6274
),

Diff for: lib/middlewares/auth_middleware.dart

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import 'package:flutter_todo_redux/pages/login_page.dart';
2+
import 'package:flutter_todo_redux/repository/user_repository.dart';
3+
import 'package:redux/redux.dart';
4+
import 'package:flutter/widgets.dart';
5+
6+
import 'package:flutter_todo_redux/actions/index.dart';
7+
import 'package:flutter_todo_redux/models/app_state.dart';
8+
import 'package:flutter_todo_redux/repository/auth_repository.dart';
9+
10+
import 'package:flutter_todo_redux/pages/home_page.dart';
11+
12+
List<Middleware<AppState>> createAuthMiddleware() {
13+
final AuthRepository repository = AuthRepository();
14+
15+
final authUser = _createAuthMiddleware(repository: repository);
16+
final unAuthUser = _createUnAuthMiddleware(repository: repository);
17+
final hasAuthed = _createHasAuthedMiddleware(repository: repository);
18+
final authSuccess = _createAuthSuccessMiddleware(repository: repository);
19+
final authFailed = _createAuthFailedMiddleware(repository: repository);
20+
final loadAuthUserList =
21+
_createLoadAuthUserListMiddleware(repository: UsersRepository());
22+
23+
return [
24+
TypedMiddleware<AppState, HasAuthenticatedAction>(hasAuthed),
25+
TypedMiddleware<AppState, AuthenticateAction>(authUser),
26+
TypedMiddleware<AppState, UnAuthenticateAction>(unAuthUser),
27+
TypedMiddleware<AppState, AuthenticateSuccessAction>(authSuccess),
28+
TypedMiddleware<AppState, AuthenticateFailedAction>(authFailed),
29+
TypedMiddleware<AppState, LoadAuthenticationUserListAction>(
30+
loadAuthUserList),
31+
];
32+
}
33+
34+
Middleware<AppState> _createHasAuthedMiddleware({
35+
@required AuthRepository repository,
36+
}) {
37+
return (Store store, action, NextDispatcher next) async {
38+
final bool hasAuthed = await repository.hasAuthenticated();
39+
40+
if (hasAuthed) {
41+
return store.dispatch(AuthenticateSuccessAction());
42+
}
43+
44+
store.dispatch(NavigateAction(routeName: LoginPage.routeName));
45+
46+
next(action);
47+
};
48+
}
49+
50+
Middleware<AppState> _createAuthMiddleware({
51+
@required AuthRepository repository,
52+
}) {
53+
return (Store store, action, NextDispatcher next) async {
54+
await repository
55+
.authenticateUser(
56+
username: action.username,
57+
password: action.password,
58+
)
59+
.then((user) => store.dispatch(AuthenticateSuccessAction()))
60+
.catchError((error) {
61+
print('Error: $error');
62+
return store.dispatch(AuthenticateFailedAction());
63+
});
64+
65+
next(action);
66+
};
67+
}
68+
69+
Middleware<AppState> _createUnAuthMiddleware({
70+
@required AuthRepository repository,
71+
}) {
72+
return (Store store, action, NextDispatcher next) async {
73+
final bool auth = await repository.unAuthenticateUser();
74+
if (!auth) {
75+
return store.dispatch(NavigateAction(routeName: LoginPage.routeName));
76+
}
77+
next(action);
78+
};
79+
}
80+
81+
Middleware<AppState> _createAuthSuccessMiddleware({
82+
@required AuthRepository repository,
83+
}) {
84+
return (Store store, action, NextDispatcher next) async {
85+
store.dispatch(NavigateAction(routeName: HomePage.routeName));
86+
87+
next(action);
88+
};
89+
}
90+
91+
Middleware<AppState> _createAuthFailedMiddleware({
92+
@required AuthRepository repository,
93+
}) {
94+
return (Store store, action, NextDispatcher next) async {
95+
next(action);
96+
};
97+
}
98+
99+
Middleware<AppState> _createLoadAuthUserListMiddleware({
100+
@required UsersRepository repository,
101+
}) {
102+
return (Store store, action, NextDispatcher next) async {
103+
await repository.getUsersList().then((userList) {
104+
return store.dispatch(AuthenticationUserListAction(userList: userList));
105+
}).catchError((error) {
106+
print('Error: $error');
107+
});
108+
109+
next(action);
110+
};
111+
}

Diff for: lib/middlewares/index.dart

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export 'todos_middleware.dart';
22
export 'navigation_middleware.dart';
3+
export 'auth_middleware.dart';

0 commit comments

Comments
 (0)