fix(apps): consolidate FormzInput validators and fix login screen

- Move FormzInput validators to core/form_inputs/form_inputs.dart
- Fix login_screen.dart syntax error (missing 'class' keyword)
- Remove unused _isLoading field
- Fix unnecessary const keywords
- Update login_cubit and register_cubit imports
- Remove duplicate FormzInput definitions from register_cubit
- Add Toast and Banner UI feedback system
- Remove legacy login/register screens (login_code, login_email, login_password, register_step2)
- Remove unused warning_banner widget
- Update tests for new error messages and DI setup
This commit is contained in:
qzl
2026-02-25 18:00:02 +08:00
parent d3bdb3ab4f
commit e20b1905cb
25 changed files with 542 additions and 608 deletions
@@ -1,10 +1,11 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:formz/formz.dart';
import 'package:equatable/equatable.dart';
import '../../../../core/api/api_exception.dart';
import '../../data/auth_repository.dart';
import '../../data/models/login_request.dart';
import '../../data/models/auth_response.dart';
import 'register_cubit.dart' show Email, Password;
import '../../../../core/form_inputs/form_inputs.dart';
class LoginState extends Equatable {
final Email email;
@@ -64,10 +65,11 @@ class LoginCubit extends Cubit<LoginState> {
emit(state.copyWith(status: FormzSubmissionStatus.success));
return response;
} catch (e) {
final message = e is ApiException ? e.message : e.toString();
emit(
state.copyWith(
status: FormzSubmissionStatus.failure,
errorMessage: e.toString(),
errorMessage: message,
),
);
return null;
@@ -1,61 +1,12 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:formz/formz.dart';
import 'package:equatable/equatable.dart';
import '../../../../core/api/api_exception.dart';
import '../../../../core/form_inputs/form_inputs.dart';
import '../../data/auth_repository.dart';
import '../../data/models/signup_request.dart';
import '../../data/models/auth_response.dart';
class Username extends FormzInput<String, String> {
const Username.pure() : super.pure('');
const Username.dirty([super.value = '']) : super.dirty();
@override
String? validator(String value) {
if (value.isEmpty) return 'Username is required';
if (value.length < 3) return 'Username must be at least 3 characters';
if (value.length > 30) return 'Username must be at most 30 characters';
return null;
}
}
class Email extends FormzInput<String, String> {
const Email.pure() : super.pure('');
const Email.dirty([super.value = '']) : super.dirty();
static final _regex = RegExp(r'^[\w.-]+@[\w.-]+\.\w+$');
@override
String? validator(String value) {
if (value.isEmpty) return 'Email is required';
if (!_regex.hasMatch(value)) return 'Invalid email format';
return null;
}
}
class Password extends FormzInput<String, String> {
const Password.pure() : super.pure('');
const Password.dirty([super.value = '']) : super.dirty();
@override
String? validator(String value) {
if (value.isEmpty) return 'Password is required';
if (value.length < 6) return 'Password must be at least 6 characters';
return null;
}
}
class VerificationCode extends FormzInput<String, String> {
const VerificationCode.pure() : super.pure('');
const VerificationCode.dirty([super.value = '']) : super.dirty();
@override
String? validator(String value) {
if (value.isEmpty) return 'Code is required';
if (!RegExp(r'^\d{6}$').hasMatch(value)) return 'Code must be 6 digits';
return null;
}
}
class RegisterState extends Equatable {
final Username username;
final Email email;
@@ -159,10 +110,11 @@ class RegisterCubit extends Cubit<RegisterState> {
);
return true;
} catch (e) {
final message = e is ApiException ? e.message : e.toString();
emit(
state.copyWith(
status: FormzSubmissionStatus.failure,
errorMessage: e.toString(),
errorMessage: message,
),
);
return false;
@@ -184,10 +136,11 @@ class RegisterCubit extends Cubit<RegisterState> {
emit(state.copyWith(status: FormzSubmissionStatus.success));
return response;
} catch (e) {
final message = e is ApiException ? e.message : e.toString();
emit(
state.copyWith(
status: FormzSubmissionStatus.failure,
errorMessage: e.toString(),
errorMessage: message,
),
);
return null;
@@ -203,7 +156,8 @@ class RegisterCubit extends Cubit<RegisterState> {
);
emit(state.copyWith(codeSent: true));
} catch (e) {
emit(state.copyWith(errorMessage: e.toString()));
final message = e is ApiException ? e.message : e.toString();
emit(state.copyWith(errorMessage: message));
}
}
}