Skip to content

Commit 5cb798d

Browse files
committed
bfix: fix textfield cursor when typed fast
Signed-off-by: Aman <aman2@me.iitr.ac.in>
1 parent 5580352 commit 5cb798d

9 files changed

Lines changed: 94 additions & 87 deletions

File tree

lib/presentation/components/inputs/form_input.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ class FormInput extends StatelessWidget {
1818
this.maxLines = 1,
1919
this.obscureText = false,
2020
this.onChanged,
21+
this.onSubmitted,
22+
this.onEditingComplete,
2123
this.prefix,
2224
Key? key,
2325
}) : assert(
@@ -34,10 +36,12 @@ class FormInput extends StatelessWidget {
3436
final String title;
3537
final String? errorText;
3638
final Function(String)? onChanged;
39+
final Function(String)? onSubmitted;
3740
final TextInputAction action;
3841
final TextInputType? keyboard;
3942
final TextEditingController? controller;
4043
final Widget? prefix;
44+
final Function()? onEditingComplete;
4145

4246
@override
4347
Widget build(BuildContext context) {
@@ -65,6 +69,8 @@ class FormInput extends StatelessWidget {
6569
controller: enabled ? controller : null,
6670
prefix: prefix,
6771
errorText: errorText,
72+
onEditingComplete: onEditingComplete,
73+
onSubmitted: onSubmitted,
6874
),
6975
],
7076
);

lib/presentation/components/inputs/text_input.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class TextInput extends StatelessWidget {
2323
this.fillColor,
2424
this.border,
2525
this.onSubmitted,
26+
this.onEditingComplete,
2627
this.prefixIconConstraints,
2728
this.validator,
2829
Key? key,
@@ -49,6 +50,7 @@ class TextInput extends StatelessWidget {
4950
final InputBorder? border;
5051
final BoxConstraints? prefixIconConstraints;
5152
final String? Function(String?)? validator;
53+
final Function()? onEditingComplete;
5254

5355
@override
5456
Widget build(BuildContext context) {
@@ -83,6 +85,7 @@ class TextInput extends StatelessWidget {
8385
onChanged: onChanged,
8486
style: AppStyles.h6.copyWith(color: AppColors.grey3),
8587
textInputAction: action,
88+
onEditingComplete: onEditingComplete,
8689
onFieldSubmitted: onSubmitted,
8790
);
8891
}

lib/presentation/contests/widgets/contest_card.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,12 +290,12 @@ extension on Ongoing {
290290
String get platformName => PlatformUtil.getName(platform);
291291
String get icon => PlatformUtil.getIcon(platform);
292292
String get time =>
293-
'Ends on ${DateFormat('dd, MMMM yyyy hh:mm a').format(endTime)}';
293+
'Ends on ${DateFormat('dd MMMM, yyyy hh:mm a').format(endTime)}';
294294
}
295295

296296
extension on Upcoming {
297297
String get platformName => PlatformUtil.getName(platform);
298298
String get icon => PlatformUtil.getIcon(platform);
299299
String get time =>
300-
'Starts on ${DateFormat('dd, MMMM yyyy hh:mm a').format(startTime)}';
300+
'Starts on ${DateFormat('dd MMMM, yyyy hh:mm a').format(startTime)}';
301301
}

lib/presentation/signup/bloc/sign_up_bloc.dart

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class SignUpBloc extends Bloc<SignUpEvent, SignUpState> {
7171
Future<void> _initialize(Initialize event, Emitter<SignUpState> emit) async {
7272
// initialize controllers
7373
final newState = state.copyWith(
74+
status: const Status(),
7475
emailController: TextEditingController(),
7576
instituteController: TextEditingController(),
7677
nameController: TextEditingController(),
@@ -188,8 +189,6 @@ class SignUpBloc extends Bloc<SignUpEvent, SignUpState> {
188189

189190
void _updatePassword(PasswordInput event, Emitter<SignUpState> emit) {
190191
emit(state.copyWith(
191-
isPasswordFocused: true,
192-
isUsernameFocused: false,
193192
passwordController: state.passwordController?.updateWith(event.value),
194193
));
195194
}
@@ -199,8 +198,6 @@ class SignUpBloc extends Bloc<SignUpEvent, SignUpState> {
199198
Emitter<SignUpState> emit,
200199
) async {
201200
emit(state.copyWith(
202-
isUsernameFocused: true,
203-
isPasswordFocused: false,
204201
usernameController: state.usernameController?.updateWith(event.value),
205202
));
206203
if (event.value.length >= 3) {
@@ -228,7 +225,8 @@ extension on TextEditingController {
228225
final controller = TextEditingController(text: value);
229226
// ignore: cascade_invocations
230227
controller.selection = TextSelection.fromPosition(
231-
TextPosition(offset: selection.baseOffset),
228+
TextPosition(offset: value.length),
229+
// TextPosition(offset: selection.baseOffset),
232230
);
233231
return controller;
234232
}

lib/presentation/signup/bloc/sign_up_state.dart

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,6 @@ class SignUpState with _$SignUpState {
1414
/// Whether the name field is in focus.
1515
@Default(false) bool isNameFocused,
1616

17-
/// Whether the password field is in focus.
18-
@Default(false) bool isPasswordFocused,
19-
20-
/// Whether the username field is in focus.
21-
@Default(false) bool isUsernameFocused,
22-
2317
/// Whether the username entered is unique.
2418
@Default(true) bool isUsernameUnique,
2519

@@ -55,7 +49,7 @@ class SignUpState with _$SignUpState {
5549
@Default({}) Map<String, TextEditingController?> handleControllers,
5650

5751
/// State of the screen.
58-
@Default(Status()) Status status,
52+
@Default(Status.loading()) Status status,
5953
}) = _SignUpState;
6054

6155
const SignUpState._();

lib/presentation/signup/signup_screen.dart

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
22
import 'package:flutter_bloc/flutter_bloc.dart';
33
import 'package:flutter_screenutil/flutter_screenutil.dart';
44

5+
import '../../domain/models/status.dart';
56
import 'bloc/sign_up_bloc.dart';
67
import 'widgets/signup_widgets.dart';
78

@@ -16,15 +17,18 @@ class SignUpScreen extends StatelessWidget {
1617
create: (_) => SignUpBloc()..add(const Initialize()),
1718
child: SnackBarWrapper(
1819
child: ScrollAndNavWrapper(
19-
child: BlocSelector<SignUpBloc, SignUpState, int>(
20-
selector: (state) => state.pageIndex,
21-
builder: (context, pageIndex) {
20+
child: BlocBuilder<SignUpBloc, SignUpState>(
21+
builder: (context, state) {
22+
if (state.status is Loading) {
23+
return Container();
24+
}
25+
2226
return Column(
2327
crossAxisAlignment: CrossAxisAlignment.start,
2428
children: <Widget>[
2529
const PopButton(),
2630
SizedBox(height: 25.r),
27-
signUpPages[pageIndex](),
31+
signUpPages[state.pageIndex](),
2832
SizedBox(height: 25.r),
2933
],
3034
);

lib/presentation/signup/widgets/pop_button.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class PopButton extends StatelessWidget {
1515
} else {
1616
return GestureDetector(
1717
onTap: () => context.read<SignUpBloc>().add(const Back()),
18-
child: SvgPicture.asset(
18+
child: svg.SvgPicture.asset(
1919
AppAssets.arrowBackward,
2020
width: 16.r,
2121
),

lib/presentation/signup/widgets/signup_pages.dart

Lines changed: 68 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ part of 'signup_widgets.dart';
22

33
Widget _pageOne() {
44
return BlocBuilder<SignUpBloc, SignUpState>(
5+
buildWhen: (previous, current) =>
6+
previous.isEmailUnique ^ current.isEmailUnique,
57
builder: (context, state) {
68
return Column(
79
crossAxisAlignment: CrossAxisAlignment.start,
@@ -27,46 +29,55 @@ Widget _pageOne() {
2729
'Institute (optional)',
2830
style: AppStyles.h4.copyWith(fontWeight: FontWeight.w900),
2931
),
32+
_buildInstituteInput(),
3033
SizedBox(height: 8.r),
31-
TypeAheadFormField<String>(
32-
onSuggestionSelected: (value) =>
33-
context.read<SignUpBloc>().add(InstituteInput(value)),
34-
itemBuilder: (context, suggestion) =>
35-
ListTile(title: Text(suggestion)),
36-
textFieldConfiguration: TextFieldConfiguration(
37-
onChanged: (value) =>
38-
context.read<SignUpBloc>().add(InstituteInput(value)),
39-
controller: state.instituteController,
40-
decoration: InputDecoration(
41-
hintText: 'Enter the name of your institute',
42-
hintStyle: AppStyles.h6,
43-
border: OutlineInputBorder(
44-
borderRadius: BorderRadius.circular(2.r),
45-
borderSide: const BorderSide(color: AppColors.primary),
46-
),
47-
focusedBorder: const OutlineInputBorder(
48-
borderSide: BorderSide(
49-
color: AppColors.primary,
50-
width: 1.5,
51-
),
52-
),
34+
],
35+
);
36+
},
37+
);
38+
}
39+
40+
Widget _buildInstituteInput() {
41+
return BlocSelector<SignUpBloc, SignUpState, TextEditingController?>(
42+
selector: (state) => state.instituteController,
43+
builder: (context, controller) {
44+
return TypeAheadFormField<String>(
45+
onSuggestionSelected: (value) =>
46+
context.read<SignUpBloc>().add(InstituteInput(value)),
47+
itemBuilder: (context, suggestion) => ListTile(title: Text(suggestion)),
48+
textFieldConfiguration: TextFieldConfiguration(
49+
onSubmitted: (value) =>
50+
context.read<SignUpBloc>().add(InstituteInput(value)),
51+
controller: controller,
52+
decoration: InputDecoration(
53+
hintText: 'Enter the name of your institute',
54+
hintStyle: AppStyles.h6,
55+
border: OutlineInputBorder(
56+
borderRadius: BorderRadius.circular(2.r),
57+
borderSide: const BorderSide(color: AppColors.primary),
58+
),
59+
focusedBorder: const OutlineInputBorder(
60+
borderSide: BorderSide(
61+
color: AppColors.primary,
62+
width: 1.5,
5363
),
5464
),
55-
suggestionsCallback: (pattern) {
56-
pattern = pattern.toLowerCase();
57-
return SignUpBloc.institutes.where(
58-
(element) => element.toLowerCase().contains(pattern),
59-
);
60-
},
6165
),
62-
],
66+
),
67+
suggestionsCallback: (pattern) {
68+
pattern = pattern.toLowerCase();
69+
return SignUpBloc.institutes.where(
70+
(element) => element.toLowerCase().contains(pattern),
71+
);
72+
},
6373
);
6474
},
6575
);
6676
}
6777

6878
Widget _pageTwo() {
6979
return BlocBuilder<SignUpBloc, SignUpState>(
80+
buildWhen: (previous, current) => false,
7081
builder: (context, state) {
7182
return Column(
7283
crossAxisAlignment: CrossAxisAlignment.start,
@@ -199,7 +210,7 @@ Widget _pageThree() {
199210
border: Border.all(color: AppColors.grey1),
200211
borderRadius: BorderRadius.circular(90.r),
201212
),
202-
child: SvgPicture.asset(
213+
child: svg.SvgPicture.asset(
203214
AppAssets.defaultUserIcon,
204215
fit: BoxFit.fill,
205216
),
@@ -245,6 +256,8 @@ Widget _pageThree() {
245256

246257
Widget _pageFour() {
247258
return BlocBuilder<SignUpBloc, SignUpState>(
259+
buildWhen: (previous, current) =>
260+
previous.obscurePassword ^ current.obscurePassword,
248261
builder: (context, state) {
249262
return Column(
250263
crossAxisAlignment: CrossAxisAlignment.start,
@@ -266,50 +279,38 @@ Widget _pageFour() {
266279
horizontal: 8.r,
267280
vertical: 10.r,
268281
),
269-
child: SvgPicture.asset(
270-
AppAssets.person,
271-
color: state.isUsernameFocused
272-
? AppColors.primary
273-
: AppColors.grey1,
282+
child: const ImageIcon(
283+
Svg(AppAssets.person),
274284
),
275285
),
276286
),
277287
SizedBox(height: 34.r),
278-
Stack(
279-
alignment: Alignment.centerRight,
280-
children: <Widget>[
281-
TextInput(
282-
action: TextInputAction.done,
283-
hint: 'Password',
284-
keyboard: TextInputType.visiblePassword,
285-
obscureText: state.obscurePassword,
286-
controller: state.passwordController,
287-
onChanged: (value) =>
288-
context.read<SignUpBloc>().add(PasswordInput(value)),
289-
prefix: Padding(
290-
padding: EdgeInsets.symmetric(
291-
horizontal: 8.r,
292-
vertical: 10.r,
293-
),
294-
child: SvgPicture.asset(
295-
AppAssets.lock,
296-
color: (state.isPasswordFocused)
297-
? AppColors.primary
298-
: AppColors.grey1,
299-
),
300-
),
288+
TextInput(
289+
action: TextInputAction.done,
290+
hint: 'Password',
291+
keyboard: TextInputType.visiblePassword,
292+
obscureText: state.obscurePassword,
293+
controller: state.passwordController,
294+
onChanged: (value) =>
295+
context.read<SignUpBloc>().add(PasswordInput(value)),
296+
prefix: Padding(
297+
padding: EdgeInsets.symmetric(
298+
horizontal: 8.r,
299+
vertical: 10.r,
301300
),
302-
IconButton(
303-
icon: SvgPicture.asset(
304-
(state.obscurePassword) ? AppAssets.eyeOff : AppAssets.eyeOn,
305-
color: state.isPasswordFocused
306-
? AppColors.primary
307-
: AppColors.grey1,
301+
child: const ImageIcon(
302+
Svg(AppAssets.lock),
303+
),
304+
),
305+
suffix: IconButton(
306+
icon: ImageIcon(
307+
Svg(
308+
state.obscurePassword ? AppAssets.eyeOff : AppAssets.eyeOn,
308309
),
309-
onPressed: () =>
310-
context.read<SignUpBloc>().add(const ToggleObscure()),
311310
),
312-
],
311+
onPressed: () =>
312+
context.read<SignUpBloc>().add(const ToggleObscure()),
313+
),
313314
),
314315
],
315316
);

lib/presentation/signup/widgets/signup_widgets.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import 'dart:io';
33
import 'package:flutter/material.dart';
44
import 'package:flutter_bloc/flutter_bloc.dart';
55
import 'package:flutter_screenutil/flutter_screenutil.dart';
6-
import 'package:flutter_svg/flutter_svg.dart';
6+
import 'package:flutter_svg/flutter_svg.dart' as svg;
7+
import 'package:flutter_svg_provider/flutter_svg_provider.dart';
78
import 'package:flutter_typeahead/flutter_typeahead.dart';
89
import 'package:get/get.dart';
910

0 commit comments

Comments
 (0)