Skip to content

Commit

Permalink
bfix: Fix textfield cursor position when typed fast.
Browse files Browse the repository at this point in the history
  • Loading branch information
BURG3R5 authored Jul 19, 2022
2 parents fd886fc + 75f3db8 commit e8c1c17
Show file tree
Hide file tree
Showing 18 changed files with 194 additions and 224 deletions.
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ buildscript {
}

dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
classpath 'com.android.tools.build:gradle:7.0.2'
classpath 'com.google.gms:google-services:4.3.8'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.7.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
Expand Down
2 changes: 1 addition & 1 deletion android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip
6 changes: 6 additions & 0 deletions lib/presentation/components/inputs/form_input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ class FormInput extends StatelessWidget {
this.maxLines = 1,
this.obscureText = false,
this.onChanged,
this.onSubmitted,
this.onEditingComplete,
this.prefix,
Key? key,
}) : assert(
Expand All @@ -34,10 +36,12 @@ class FormInput extends StatelessWidget {
final String title;
final String? errorText;
final Function(String)? onChanged;
final Function(String)? onSubmitted;
final TextInputAction action;
final TextInputType? keyboard;
final TextEditingController? controller;
final Widget? prefix;
final Function()? onEditingComplete;

@override
Widget build(BuildContext context) {
Expand Down Expand Up @@ -65,6 +69,8 @@ class FormInput extends StatelessWidget {
controller: enabled ? controller : null,
prefix: prefix,
errorText: errorText,
onEditingComplete: onEditingComplete,
onSubmitted: onSubmitted,
),
],
);
Expand Down
3 changes: 3 additions & 0 deletions lib/presentation/components/inputs/text_input.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class TextInput extends StatelessWidget {
this.fillColor,
this.border,
this.onSubmitted,
this.onEditingComplete,
this.prefixIconConstraints,
this.validator,
Key? key,
Expand All @@ -49,6 +50,7 @@ class TextInput extends StatelessWidget {
final InputBorder? border;
final BoxConstraints? prefixIconConstraints;
final String? Function(String?)? validator;
final Function()? onEditingComplete;

@override
Widget build(BuildContext context) {
Expand Down Expand Up @@ -83,6 +85,7 @@ class TextInput extends StatelessWidget {
onChanged: onChanged,
style: AppStyles.h6.copyWith(color: AppColors.grey3),
textInputAction: action,
onEditingComplete: onEditingComplete,
onFieldSubmitted: onSubmitted,
);
}
Expand Down
4 changes: 2 additions & 2 deletions lib/presentation/contests/widgets/contest_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -290,12 +290,12 @@ extension on Ongoing {
String get platformName => PlatformUtil.getName(platform);
String get icon => PlatformUtil.getIcon(platform);
String get time =>
'Ends on ${DateFormat('dd, MMMM yyyy hh:mm a').format(endTime)}';
'Ends on ${DateFormat('dd MMMM, yyyy hh:mm a').format(endTime)}';
}

extension on Upcoming {
String get platformName => PlatformUtil.getName(platform);
String get icon => PlatformUtil.getIcon(platform);
String get time =>
'Starts on ${DateFormat('dd, MMMM yyyy hh:mm a').format(startTime)}';
'Starts on ${DateFormat('dd MMMM, yyyy hh:mm a').format(startTime)}';
}
14 changes: 2 additions & 12 deletions lib/presentation/login/bloc/login_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> {
if (!state.isFormFilled()) return;

emit(state.copyWith(
isPasswordFocused: false,
isUsernameFocused: false,
status: const Status.loading(),
));

Expand Down Expand Up @@ -84,18 +82,10 @@ class LoginBloc extends Bloc<LoginEvent, LoginState> {
}

void _updatePasswordInput(PasswordInput event, Emitter<LoginState> emit) {
emit(state.copyWith(
isPasswordFocused: true,
isUsernameFocused: false,
password: event.value,
));
emit(state.copyWith(password: event.value));
}

void _updateUsernameInput(UsernameInput event, Emitter<LoginState> emit) {
emit(state.copyWith(
isUsernameFocused: true,
isPasswordFocused: false,
username: event.value,
));
emit(state.copyWith(username: event.value));
}
}
6 changes: 0 additions & 6 deletions lib/presentation/login/bloc/login_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,6 @@ part of 'login_bloc.dart';
class LoginState with _$LoginState {
/// State class for [LoginBloc].
const factory LoginState({
/// Whether the username field is in focus.
@Default(false) bool isUsernameFocused,

/// Whether the password field is in focus.
@Default(false) bool isPasswordFocused,

/// Whether the password field should be obscured.
@Default(true) bool obscurePassword,

Expand Down
4 changes: 2 additions & 2 deletions lib/presentation/login/widgets/background_decoration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ class BackgroundDecoration extends StatelessWidget {
Positioned(
top: 0,
left: 0,
child: SvgPicture.asset(
child: svg.SvgPicture.asset(
AppAssets.circle1,
width: 170.r,
),
),
Positioned(
top: 80.r,
right: 0,
child: SvgPicture.asset(
child: svg.SvgPicture.asset(
AppAssets.triangle,
width: 140.r,
),
Expand Down
3 changes: 2 additions & 1 deletion lib/presentation/login/widgets/login_widgets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_svg/flutter_svg.dart' as svg;
import 'package:flutter_svg_provider/flutter_svg_provider.dart';
import 'package:get/get.dart';

import '../../../data/constants/assets.dart';
Expand Down
93 changes: 38 additions & 55 deletions lib/presentation/login/widgets/text_fields.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,35 @@ class PasswordField extends StatelessWidget {

@override
Widget build(BuildContext context) {
// [BlocSelector] is not used because widget depends on both
// [state.isPasswordFocused] and [state.obscurePassword].
return BlocBuilder<LoginBloc, LoginState>(
builder: (context, state) {
return Stack(
alignment: Alignment.centerRight,
children: <Widget>[
TextInput(
action: TextInputAction.done,
hint: 'Password',
keyboard: TextInputType.visiblePassword,
obscureText: state.obscurePassword,
onChanged: (value) =>
context.read<LoginBloc>().add(PasswordInput(value)),
prefix: Padding(
padding: EdgeInsets.symmetric(
horizontal: 8.r,
vertical: 10.r,
),
child: SvgPicture.asset(
AppAssets.lock,
// TODO(BURG3R5): Deal with Focus transfer.
color: (state.isPasswordFocused)
? AppColors.primary
: AppColors.grey1,
),
),
return BlocSelector<LoginBloc, LoginState, bool>(
selector: (state) => state.obscurePassword,
builder: (context, obscurePassword) {
return TextInput(
action: TextInputAction.done,
hint: 'Password',
keyboard: TextInputType.visiblePassword,
obscureText: obscurePassword,
onChanged: (value) =>
context.read<LoginBloc>().add(PasswordInput(value)),
prefix: Padding(
padding: EdgeInsets.symmetric(
horizontal: 8.r,
vertical: 10.r,
),
// TODO(BURG3R5): Deal with Focus transfer.
child: const ImageIcon(
Svg(AppAssets.lock),
),
IconButton(
icon: SvgPicture.asset(
(state.obscurePassword) ? AppAssets.eyeOff : AppAssets.eyeOn,
color: state.isPasswordFocused
? AppColors.primary
: AppColors.grey1,
),
suffix: IconButton(
icon: ImageIcon(
Svg(
obscurePassword ? AppAssets.eyeOff : AppAssets.eyeOn,
),
onPressed: () =>
context.read<LoginBloc>().add(const ToggleObscure()),
),
],
onPressed: () =>
context.read<LoginBloc>().add(const ToggleObscure()),
),
);
},
);
Expand All @@ -59,25 +49,18 @@ class UsernameField extends StatelessWidget {

@override
Widget build(BuildContext context) {
return BlocSelector<LoginBloc, LoginState, bool>(
selector: (state) => state.isUsernameFocused,
builder: (context, isUsernameFocused) {
return TextInput(
hint: 'Username',
onChanged: (value) =>
context.read<LoginBloc>().add(UsernameInput(value)),
prefix: Padding(
padding: EdgeInsets.symmetric(
horizontal: 8.r,
vertical: 10.r,
),
child: SvgPicture.asset(
AppAssets.person,
color: isUsernameFocused ? AppColors.primary : AppColors.grey1,
),
),
);
},
return TextInput(
hint: 'Username',
onChanged: (value) => context.read<LoginBloc>().add(UsernameInput(value)),
prefix: Padding(
padding: EdgeInsets.symmetric(
horizontal: 8.r,
vertical: 10.r,
),
child: const ImageIcon(
Svg(AppAssets.person),
),
),
);
}
}
8 changes: 3 additions & 5 deletions lib/presentation/signup/bloc/sign_up_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class SignUpBloc extends Bloc<SignUpEvent, SignUpState> {
Future<void> _initialize(Initialize event, Emitter<SignUpState> emit) async {
// initialize controllers
final newState = state.copyWith(
status: const Status(),
emailController: TextEditingController(),
instituteController: TextEditingController(),
nameController: TextEditingController(),
Expand Down Expand Up @@ -188,8 +189,6 @@ class SignUpBloc extends Bloc<SignUpEvent, SignUpState> {

void _updatePassword(PasswordInput event, Emitter<SignUpState> emit) {
emit(state.copyWith(
isPasswordFocused: true,
isUsernameFocused: false,
passwordController: state.passwordController?.updateWith(event.value),
));
}
Expand All @@ -199,8 +198,6 @@ class SignUpBloc extends Bloc<SignUpEvent, SignUpState> {
Emitter<SignUpState> emit,
) async {
emit(state.copyWith(
isUsernameFocused: true,
isPasswordFocused: false,
usernameController: state.usernameController?.updateWith(event.value),
));
if (event.value.length >= 3) {
Expand Down Expand Up @@ -228,7 +225,8 @@ extension on TextEditingController {
final controller = TextEditingController(text: value);
// ignore: cascade_invocations
controller.selection = TextSelection.fromPosition(
TextPosition(offset: selection.baseOffset),
TextPosition(offset: value.length),
// TextPosition(offset: selection.baseOffset),
);
return controller;
}
Expand Down
8 changes: 1 addition & 7 deletions lib/presentation/signup/bloc/sign_up_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,6 @@ class SignUpState with _$SignUpState {
/// Whether the name field is in focus.
@Default(false) bool isNameFocused,

/// Whether the password field is in focus.
@Default(false) bool isPasswordFocused,

/// Whether the username field is in focus.
@Default(false) bool isUsernameFocused,

/// Whether the username entered is unique.
@Default(true) bool isUsernameUnique,

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

/// State of the screen.
@Default(Status()) Status status,
@Default(Status.loading()) Status status,
}) = _SignUpState;

const SignUpState._();
Expand Down
12 changes: 8 additions & 4 deletions lib/presentation/signup/signup_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

import '../../domain/models/status.dart';
import 'bloc/sign_up_bloc.dart';
import 'widgets/signup_widgets.dart';

Expand All @@ -16,15 +17,18 @@ class SignUpScreen extends StatelessWidget {
create: (_) => SignUpBloc()..add(const Initialize()),
child: SnackBarWrapper(
child: ScrollAndNavWrapper(
child: BlocSelector<SignUpBloc, SignUpState, int>(
selector: (state) => state.pageIndex,
builder: (context, pageIndex) {
child: BlocBuilder<SignUpBloc, SignUpState>(
builder: (context, state) {
if (state.status is Loading) {
return Container();
}

return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const PopButton(),
SizedBox(height: 25.r),
signUpPages[pageIndex](),
signUpPages[state.pageIndex](),
SizedBox(height: 25.r),
],
);
Expand Down
2 changes: 1 addition & 1 deletion lib/presentation/signup/widgets/pop_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class PopButton extends StatelessWidget {
} else {
return GestureDetector(
onTap: () => context.read<SignUpBloc>().add(const Back()),
child: SvgPicture.asset(
child: svg.SvgPicture.asset(
AppAssets.arrowBackward,
width: 16.r,
),
Expand Down
Loading

0 comments on commit e8c1c17

Please sign in to comment.