Skip to content

Commit e2b3918

Browse files
committed
Migrate to null-safety
1 parent 16f41b7 commit e2b3918

File tree

6 files changed

+69
-64
lines changed

6 files changed

+69
-64
lines changed

lib/config/consts.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
class Consts {
2-
static const neutralState = 0;
3-
static const correctState = 1;
4-
static const halfCorrectState = -1;
5-
static const incorrectState = -2;
2+
static const String neutralState = "0";
3+
static const String correctState = "1";
4+
static const String halfCorrectState = "-1";
5+
static const String incorrectState = "-2";
66
static const String returnSymbol = "\u23CE";
77
}

lib/screens/main/mainScreen.dart

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,32 +20,33 @@ class MainScreen extends StatefulHookWidget {
2020

2121
class _MainScreenState extends State<MainScreen> {
2222
final TypeTestBox _typeTestBox = TypeTestBox();
23-
FocusNode _typeTestFocusNode;
24-
ResultsSideBar _resultsSideBar;
23+
FocusNode? _typeTestFocusNode;
24+
ResultsSideBar? _resultsSideBar;
2525
String _typeTestText = '';
26-
List<List> _charactersData = [];
26+
List<List<String>> _charactersData = [];
2727
Map<String, int> _mistakes = {};
2828
int _cursorIndex = 0;
2929
int _accuracy = 0;
30-
DateTime _startTime;
30+
DateTime? _startTime;
3131
bool _isRestarting = false;
3232

3333
//String _debugText = '';
3434

3535
/// Gets the 5 most frequent mistakes from [_mistakes].
3636
List<String> _getCommonMistakes() {
3737
List _sortedMistakes = _mistakes.keys.toList(growable: false)
38-
..sort((k1, k2) => _mistakes[k2].compareTo(_mistakes[k1]));
38+
..sort((k1, k2) => _mistakes[k2]!.compareTo(_mistakes[k1]!));
3939
return _sortedMistakes.sublist(
40-
0, _sortedMistakes.length < 5 ? _sortedMistakes.length : 5);
40+
0, _sortedMistakes.length < 5 ? _sortedMistakes.length : 5)
41+
as List<String>;
4142
}
4243

4344
/// Calculates the WPM, accuracy and common mistakes and updates the [_resultsSideBar].
4445
void _updateResultsSideBar() {
4546
final double wpm = (_cursorIndex / 5) /
46-
(DateTime.now().difference(_startTime).inMilliseconds / 60000);
47+
(DateTime.now().difference(_startTime!).inMilliseconds / 60000);
4748
final double accuracy = _accuracy / _cursorIndex;
48-
_resultsSideBar.update(
49+
_resultsSideBar!.update(
4950
wpm: wpm,
5051
accuracy: accuracy,
5152
commonMistakes: _getCommonMistakes(),
@@ -67,12 +68,13 @@ class _MainScreenState extends State<MainScreen> {
6768
// Create a new list of characters from newText.
6869
newText.replaceAll('\n', Consts.returnSymbol).split('').forEach(
6970
// first element is the actual character string, second element is the state of the character.
70-
(character) => _charactersData.add([character, Consts.correctState]),
71+
(String character) =>
72+
_charactersData.add([character, Consts.correctState]),
7173
);
7274

7375
// Resets the ResultsSideBar.
74-
_resultsSideBar.update(
75-
wpm: 0, accuracy: 0, commonMistakes: _getCommonMistakes());
76+
_resultsSideBar!
77+
.update(wpm: 0, accuracy: 0, commonMistakes: _getCommonMistakes());
7678

7779
// Rebuilds the TypeTestBoxCharacters in the TypeTestBox.
7880
_typeTestBox.generateCharacters(_charactersData);
@@ -82,7 +84,7 @@ class _MainScreenState extends State<MainScreen> {
8284
//_typeTestFocusNode.requestFocus(); // <-- this doesn't work on release app for some reason??!!
8385

8486
// Once all the widgets are built we can allow key presses again.
85-
WidgetsBinding.instance.addPostFrameCallback(
87+
WidgetsBinding.instance!.addPostFrameCallback(
8688
(_) => _isRestarting = false,
8789
);
8890
}
@@ -109,7 +111,7 @@ class _MainScreenState extends State<MainScreen> {
109111
}
110112

111113
/// Validates the key press and updates the test data and widgets accordingly.
112-
void _validateInput(String input) {
114+
void _validateInput(String? input) {
113115
// True if backspace is pressed and the cursor isn't at the start of the test.
114116
if (input == "Backspace") {
115117
if (_cursorIndex > 0) {
@@ -143,7 +145,9 @@ class _MainScreenState extends State<MainScreen> {
143145
_charactersData[_cursorIndex][1] = Consts.incorrectState;
144146
// Increases the number of incorrect types for the current character in _mistakes.
145147
if (_mistakes.containsKey(_charactersData[_cursorIndex][0]))
146-
_mistakes[_charactersData[_cursorIndex][0]]++;
148+
_mistakes[_charactersData[_cursorIndex][0]] =
149+
_mistakes[_charactersData[_cursorIndex][0]]! +
150+
1; // <-- Any other way of doing this with null-safty??
147151
else
148152
_mistakes[_charactersData[_cursorIndex][0]] = 1;
149153
}
@@ -164,7 +168,7 @@ class _MainScreenState extends State<MainScreen> {
164168
index: _cursorIndex, state: Consts.neutralState, isAtCursor: true);
165169
// Prevents listening to key inputs if the cursor is at the end of the test.
166170
else {
167-
_typeTestFocusNode.unfocus();
171+
_typeTestFocusNode!.unfocus();
168172
FocusScope.of(context).requestFocus(FocusNode());
169173
}
170174
// Updates the ResultSideBar with the new results.
@@ -180,7 +184,7 @@ class _MainScreenState extends State<MainScreen> {
180184
_resultsSideBar = ResultsSideBar(onRestart: () => _restart(_typeTestText));
181185

182186
// Starts a test with the initial type text once everything has been built.
183-
WidgetsBinding.instance.addPostFrameCallback(
187+
WidgetsBinding.instance!.addPostFrameCallback(
184188
(_) => _restart(Config.initialTypeTestText),
185189
);
186190
}
@@ -194,7 +198,7 @@ class _MainScreenState extends State<MainScreen> {
194198
final FocusNode textInputFocusNode = useFocusNode();
195199

196200
// Gets the controller for the TextInputBox.
197-
final TextEditingController textInputController =
201+
final TextEditingController? textInputController =
198202
useTextEditingController();
199203

200204
return Scaffold(
@@ -210,7 +214,7 @@ class _MainScreenState extends State<MainScreen> {
210214
),*/
211215
Expanded(
212216
child: RawKeyboardListener(
213-
focusNode: _typeTestFocusNode,
217+
focusNode: _typeTestFocusNode!,
214218
onKey: _onKey,
215219
child: _typeTestBox,
216220
),
@@ -223,7 +227,7 @@ class _MainScreenState extends State<MainScreen> {
223227
],
224228
),
225229
),
226-
_resultsSideBar,
230+
_resultsSideBar!,
227231
],
228232
),
229233
);

lib/screens/main/resultsSideBar.dart

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import 'package:typetypego/config/palette.dart';
66
/// The blue container with 3 circular percent indicators that displays the results of the typing test.
77
class ResultsSideBar extends StatefulWidget {
88
/// Called when the restart button is pressed.
9-
final Function onRestart;
9+
final Function? onRestart;
1010

1111
ResultsSideBar({this.onRestart});
1212

@@ -17,9 +17,9 @@ class ResultsSideBar extends StatefulWidget {
1717

1818
/// Updates the circular percent indicators with the new wpm, accuracy and common mistakes results.
1919
void update(
20-
{@required double wpm,
21-
@required double accuracy,
22-
@required List<String> commonMistakes}) =>
20+
{required double wpm,
21+
required double accuracy,
22+
required List<String> commonMistakes}) =>
2323
_resultsSideBarState.update(
2424
wpm: wpm, accuracy: accuracy, commonMistakes: commonMistakes);
2525
}
@@ -38,9 +38,9 @@ class _ResultsSideBarState extends State<ResultsSideBar> {
3838
/// Rebuilding like this instead of calling [setState()] on the [MainScreen] prevents everything from being rebuilt
3939
/// everytime a key is pressed.
4040
void update(
41-
{@required double wpm,
42-
@required double accuracy,
43-
@required List<String> commonMistakes}) {
41+
{required double wpm,
42+
required double accuracy,
43+
required List<String> commonMistakes}) {
4444
setState(() {
4545
_wpm = wpm;
4646
_wpmPercent = _wpm / Config.wpmTarget;
@@ -121,7 +121,7 @@ class _ResultsSideBarState extends State<ResultsSideBar> {
121121
icon: Icon(Icons.refresh_rounded),
122122
iconSize: 75,
123123
color: Palette.white,
124-
onPressed: widget.onRestart,
124+
onPressed: widget.onRestart as void Function()?,
125125
),
126126
],
127127
),
@@ -138,7 +138,7 @@ class ResultsCircularPercentIndicator extends StatelessWidget {
138138
final String title;
139139

140140
ResultsCircularPercentIndicator(
141-
{@required this.percent, @required this.valueText, @required this.title});
141+
{required this.percent, required this.valueText, required this.title});
142142

143143
@override
144144
Widget build(BuildContext context) {
@@ -185,7 +185,7 @@ class ResultsCircularPercentIndicator extends StatelessWidget {
185185
class ResultsMistakeCharacter extends StatelessWidget {
186186
final String character;
187187

188-
ResultsMistakeCharacter({@required this.character});
188+
ResultsMistakeCharacter({required this.character});
189189

190190
@override
191191
Widget build(BuildContext context) {

lib/screens/main/textInputBox.dart

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,25 @@ class TextInputBox extends StatelessWidget {
1010
final FocusNode focusNode;
1111

1212
/// The controller for the text field.
13-
final TextEditingController controller;
13+
final TextEditingController? controller;
1414

1515
/// Called when the start button is pressed.
1616
///
1717
/// * [String] = the validated text from the text field.
18-
final Function(String) onStart;
18+
final Function(String)? onStart;
1919

2020
TextInputBox(
21-
{@required this.focusNode, @required this.controller, this.onStart});
21+
{required this.focusNode, required this.controller, this.onStart});
2222

2323
// The form key for the text field.
2424
final _formKey = GlobalKey<FormState>();
2525

2626
/// Validates the text from the [TextInputBoxTextField],
2727
/// unfocuses the [focusNode] and calls [onStart()].
2828
void _validate() {
29-
if (_formKey.currentState.validate()) {
29+
if (_formKey.currentState!.validate()) {
3030
focusNode.unfocus();
31-
onStart(controller.text.trim());
31+
onStart!(controller!.text.trim());
3232
}
3333
}
3434

@@ -70,16 +70,16 @@ class TextInputBox extends StatelessWidget {
7070

7171
/// The text field displayed in the [TextInputBox].
7272
class TextInputBoxTextField extends StatelessWidget {
73-
final TextEditingController controller;
73+
final TextEditingController? controller;
7474
final FocusNode focusNode;
7575
final GlobalKey formKey;
7676
final int maxWordLength;
7777

7878
TextInputBoxTextField(
79-
{@required this.controller,
80-
@required this.focusNode,
81-
@required this.formKey,
82-
@required this.maxWordLength});
79+
{required this.controller,
80+
required this.focusNode,
81+
required this.formKey,
82+
required this.maxWordLength});
8383

8484
@override
8585
Widget build(BuildContext context) {
@@ -91,7 +91,7 @@ class TextInputBoxTextField extends StatelessWidget {
9191
controller: controller,
9292
focusNode: focusNode,
9393
validator: (value) {
94-
final String trimmedValue = value.trim();
94+
final String trimmedValue = value!.trim();
9595
// True if the text field is empty.
9696
if (trimmedValue.isEmpty)
9797
return 'Paste some text in here and then click "GO!" to start';
@@ -143,7 +143,7 @@ class TextInputBoxTextField extends StatelessWidget {
143143
/// The button thats starts the test in the [TextInputBox].
144144
class TextInputBoxStartButton extends StatelessWidget {
145145
/// Called when this button is pressed.
146-
final Function onPressed;
146+
final Function? onPressed;
147147

148148
TextInputBoxStartButton({this.onPressed});
149149

@@ -158,6 +158,7 @@ class TextInputBoxStartButton extends StatelessWidget {
158158
borderRadius: BorderRadius.circular(200),
159159
),
160160
primary: Palette.blue,
161+
padding: EdgeInsets.fromLTRB(30, 0, 30, 0),
161162
),
162163
child: Text(
163164
'GO!',
@@ -167,7 +168,7 @@ class TextInputBoxStartButton extends StatelessWidget {
167168
fontSize: 24,
168169
),
169170
),
170-
onPressed: onPressed,
171+
onPressed: onPressed as void Function()?,
171172
),
172173
);
173174
}

lib/screens/main/typeTestBox.dart

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ class TypeTestBox extends StatefulWidget {
1616

1717
/// Rebuilds the [TypeTestBoxCharacter] at [index] with the new [state] and [isAtCursor].
1818
void updateCharacter(
19-
{@required int index,
20-
@required int state,
21-
@required bool isAtCursor}) =>
19+
{required int index,
20+
required String state,
21+
required bool isAtCursor}) =>
2222
_typeTestBoxState.updateCharacter(
2323
index: index, state: state, isAtCursor: isAtCursor);
2424
}
@@ -107,9 +107,9 @@ class _TypeTestBoxState extends State<TypeTestBox> {
107107
///
108108
/// Rebuilding like this instead of calling [setState()] prevents all the other [TypeTestBoxCharacter]s from being rebuilt.
109109
void updateCharacter(
110-
{@required int index,
111-
@required int state,
112-
@required bool isAtCursor}) =>
110+
{required int index,
111+
required String state,
112+
required bool isAtCursor}) =>
113113
_characters[index].update(state, isAtCursor);
114114

115115
@override
@@ -139,15 +139,15 @@ class _TypeTestBoxState extends State<TypeTestBox> {
139139

140140
/// Represents a character of the type test text displayed in the [TypeTestBox].
141141
class TypeTestBoxCharacter extends StatefulWidget {
142-
final String character;
142+
final String? character;
143143
final bool initialIsAtCursor;
144144

145145
/// This is needed to make sure it's visible.
146146
final GlobalKey key;
147147

148148
TypeTestBoxCharacter(
149-
{@required this.key,
150-
@required this.character,
149+
{required this.key,
150+
required this.character,
151151
this.initialIsAtCursor = false})
152152
: super(key: key);
153153

@@ -158,23 +158,23 @@ class TypeTestBoxCharacter extends StatefulWidget {
158158
_TypeTestBoxCharacterState createState() => _typeTestBoxCharacterState;
159159

160160
/// Rebuilds this with the new [state] and [isAtCursor].
161-
void update(int state, bool isAtCursor) =>
161+
void update(String state, bool isAtCursor) =>
162162
_typeTestBoxCharacterState.update(state, isAtCursor);
163163
}
164164

165165
class _TypeTestBoxCharacterState extends State<TypeTestBoxCharacter> {
166-
int _state = 0;
166+
String _state = Consts.neutralState;
167167
bool _isAtCursor = false;
168168

169169
/// Rebuilds this with the new [state] and [isAtCursor].
170-
void update(int state, bool isAtCursor) {
170+
void update(String state, bool isAtCursor) {
171171
setState(() {
172172
_state = state;
173173
_isAtCursor = isAtCursor;
174174

175175
if (isAtCursor)
176176
// Scroll down to it's position in the ListView if it's not visible
177-
Scrollable.ensureVisible(widget.key.currentContext, alignment: 0.25);
177+
Scrollable.ensureVisible(widget.key.currentContext!, alignment: 0.25);
178178
});
179179
}
180180

@@ -211,7 +211,7 @@ class _TypeTestBoxCharacterState extends State<TypeTestBoxCharacter> {
211211
),
212212
),
213213
child: Text(
214-
widget.character,
214+
widget.character!,
215215
style: TextStyle(
216216
fontSize: 24,
217217
color: Palette.white,

pubspec.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,16 @@ publish_to: 'none'
1818
version: 1.0.2+1
1919

2020
environment:
21-
sdk: ">=2.7.0 <3.0.0"
21+
sdk: '>=2.12.0 <3.0.0'
2222

2323
dependencies:
2424
flutter:
2525
sdk: flutter
2626

2727

28-
percent_indicator: ^2.1.9
29-
flutter_hooks: ^0.15.0
30-
responsive_builder: ^0.3.0
28+
percent_indicator: ^3.3.0-nullsafety.1
29+
flutter_hooks: ^0.16.0
30+
responsive_builder: ^0.4.0-nullsafety.1
3131

3232
dev_dependencies:
3333
flutter_test:

0 commit comments

Comments
 (0)