This repository has been archived by the owner on Sep 3, 2023. It is now read-only.
/
main.dart
118 lines (101 loc) · 3.15 KB
/
main.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import 'package:flutter/material.dart';
import 'package:reactives/reactives.dart';
/// Simple widget showing reactive
class LoginWidget extends StatefulWidget {
const LoginWidget({Key? key}) : super(key: key);
@override
_LoginWidgetState createState() => _LoginWidgetState();
}
// Add the ReactiveHostMixin
class _LoginWidgetState extends State<LoginWidget> with ReactiveHostMixin {
// Create required reactives
late final emailCtrl = ReactiveTextEditingController(this).ctrl;
late final passwordCtrl = ReactiveTextEditingController(this).ctrl;
var passwordVisible = false;
void submit() {
// Login logic
}
void toggeVisible() {
setState(() {
passwordVisible = !passwordVisible;
});
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
// Use the reactives just like any field
TextField(controller: emailCtrl),
TextField(
controller: passwordCtrl,
decoration: InputDecoration(
suffix: IconButton(
icon: const Icon(Icons.visibility),
onPressed: toggeVisible,
),
),
obscureText: !passwordVisible,
),
ElevatedButton(
child: const Text('Login'),
onPressed: submit,
),
],
);
}
}
/// ReactiveLogin is a way to extract the login logic out of the widget for
/// testability and resusability
class ReactiveLogin extends Reactive {
final ReactiveTextEditingController _email;
final ReactiveTextEditingController _password;
TextEditingController get emailCtrl => _email.ctrl;
TextEditingController get passwordCtrl => _password.ctrl;
bool _passwordVisible = false;
bool get passwordVisible => _passwordVisible;
ReactiveLogin(ReactiveHost host)
: _email = ReactiveTextEditingController(host),
_password = ReactiveTextEditingController(host),
super(host);
void submit() {
// Login logic
}
void toggleVisible() {
_passwordVisible = !_passwordVisible;
host.requestUpdate(); // Calls setState
}
}
/// The above example can be rewritten using our extracted login logic
/// This reduces the Widget the UI logic
class LoginView extends StatefulWidget {
const LoginView({Key? key}) : super(key: key);
@override
_LoginViewState createState() => _LoginViewState();
}
// Add the ReactiveHostMixin
class _LoginViewState extends State<LoginView> with ReactiveHostMixin {
// Create required login Reactive
late final login = ReactiveLogin(this);
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
// Use the reactives just like any field
TextField(controller: login.emailCtrl),
TextField(
controller: login.passwordCtrl,
decoration: InputDecoration(
suffix: IconButton(
icon: const Icon(Icons.visibility),
onPressed: login.toggleVisible,
),
),
obscureText: !login.passwordVisible,
),
ElevatedButton(child: const Text('Login'), onPressed: login.submit),
],
);
}
}