Fix: Resolve critical linting issues and bugs (concurrency, syntax, dead code)

This commit is contained in:
2026-02-10 19:12:01 +05:30
parent 5e7bf0d5c0
commit 7570ffa3b9
46 changed files with 4057 additions and 1299 deletions

View File

@@ -1,6 +1,7 @@
import 'dart:async';
import 'package:flutter_modular/flutter_modular.dart';
import 'package:bloc/bloc.dart';
import 'package:krow_core/core.dart';
import 'package:krow_domain/krow_domain.dart';
import '../../domain/arguments/sign_in_with_phone_arguments.dart';
import '../../domain/arguments/verify_otp_arguments.dart';
@@ -10,7 +11,9 @@ import 'auth_event.dart';
import 'auth_state.dart';
/// BLoC responsible for handling authentication logic.
class AuthBloc extends Bloc<AuthEvent, AuthState> implements Disposable {
class AuthBloc extends Bloc<AuthEvent, AuthState>
with BlocErrorHandler<AuthState>
implements Disposable {
/// The use case for signing in with a phone number.
final SignInWithPhoneUseCase _signInUseCase;
@@ -84,7 +87,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> implements Disposable {
status: AuthStatus.error,
mode: event.mode,
phoneNumber: event.phoneNumber ?? state.phoneNumber,
errorMessage: 'Please wait ${remaining}s before requesting a new code.',
errorMessage:
'Please wait ${remaining}s before requesting a new code.',
cooldownSecondsRemaining: remaining,
),
);
@@ -105,39 +109,40 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> implements Disposable {
cooldownSecondsRemaining: 0,
),
);
try {
final String? verificationId = await _signInUseCase(
SignInWithPhoneArguments(
phoneNumber: event.phoneNumber ?? state.phoneNumber,
),
);
if (token != _requestToken) return;
emit(
state.copyWith(
status: AuthStatus.codeSent,
verificationId: verificationId,
cooldownSecondsRemaining: 0,
),
);
} catch (e) {
if (token != _requestToken) return;
emit(
state.copyWith(
await handleError(
emit: emit,
action: () async {
final String? verificationId = await _signInUseCase(
SignInWithPhoneArguments(
phoneNumber: event.phoneNumber ?? state.phoneNumber,
),
);
if (token != _requestToken) return;
emit(
state.copyWith(
status: AuthStatus.codeSent,
verificationId: verificationId,
cooldownSecondsRemaining: 0,
),
);
},
onError: (String errorKey) {
if (token != _requestToken) return state;
return state.copyWith(
status: AuthStatus.error,
errorMessage: e.toString(),
errorMessage: errorKey,
cooldownSecondsRemaining: 0,
),
);
}
);
},
);
}
void _onCooldownTicked(
AuthCooldownTicked event,
Emitter<AuthState> emit,
) {
print('Auth cooldown tick: ${event.secondsRemaining}');
if (event.secondsRemaining <= 0) {
print('Auth cooldown finished: clearing message');
_cancelCooldownTimer();
_cooldownUntil = null;
emit(
@@ -166,11 +171,9 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> implements Disposable {
add(AuthCooldownTicked(remaining));
_cooldownTimer = Timer.periodic(const Duration(seconds: 1), (Timer timer) {
remaining -= 1;
print('Auth cooldown timer: remaining=$remaining');
if (remaining <= 0) {
timer.cancel();
_cooldownTimer = null;
print('Auth cooldown timer: reached 0, emitting tick');
add(const AuthCooldownTicked(0));
return;
}
@@ -183,27 +186,29 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> implements Disposable {
_cooldownTimer = null;
}
/// Handles OTP submission and verification.
Future<void> _onOtpSubmitted(
AuthOtpSubmitted event,
Emitter<AuthState> emit,
) async {
emit(state.copyWith(status: AuthStatus.loading));
try {
final User? user = await _verifyOtpUseCase(
VerifyOtpArguments(
verificationId: event.verificationId,
smsCode: event.smsCode,
mode: event.mode,
),
);
emit(state.copyWith(status: AuthStatus.authenticated, user: user));
} catch (e) {
emit(
state.copyWith(status: AuthStatus.error, errorMessage: e.toString()),
);
}
await handleError(
emit: emit,
action: () async {
final User? user = await _verifyOtpUseCase(
VerifyOtpArguments(
verificationId: event.verificationId,
smsCode: event.smsCode,
mode: event.mode,
),
);
emit(state.copyWith(status: AuthStatus.authenticated, user: user));
},
onError: (String errorKey) => state.copyWith(
status: AuthStatus.error,
errorMessage: errorKey,
),
);
}
/// Disposes the BLoC resources.
@@ -213,3 +218,4 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> implements Disposable {
close();
}
}

View File

@@ -1,4 +1,5 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:krow_core/core.dart';
import '../../../domain/usecases/submit_profile_setup_usecase.dart';
import '../../../domain/usecases/search_cities_usecase.dart';
@@ -10,7 +11,8 @@ export 'profile_setup_event.dart';
export 'profile_setup_state.dart';
/// BLoC responsible for managing the profile setup state and logic.
class ProfileSetupBloc extends Bloc<ProfileSetupEvent, ProfileSetupState> {
class ProfileSetupBloc extends Bloc<ProfileSetupEvent, ProfileSetupState>
with BlocErrorHandler<ProfileSetupState> {
ProfileSetupBloc({
required SubmitProfileSetup submitProfileSetup,
required SearchCitiesUseCase searchCities,
@@ -86,25 +88,25 @@ class ProfileSetupBloc extends Bloc<ProfileSetupEvent, ProfileSetupState> {
) async {
emit(state.copyWith(status: ProfileSetupStatus.loading));
try {
await _submitProfileSetup(
fullName: state.fullName,
bio: state.bio.isEmpty ? null : state.bio,
preferredLocations: state.preferredLocations,
maxDistanceMiles: state.maxDistanceMiles,
industries: state.industries,
skills: state.skills,
);
await handleError(
emit: emit,
action: () async {
await _submitProfileSetup(
fullName: state.fullName,
bio: state.bio.isEmpty ? null : state.bio,
preferredLocations: state.preferredLocations,
maxDistanceMiles: state.maxDistanceMiles,
industries: state.industries,
skills: state.skills,
);
emit(state.copyWith(status: ProfileSetupStatus.success));
} catch (e) {
emit(
state.copyWith(
status: ProfileSetupStatus.failure,
errorMessage: e.toString(),
),
);
}
emit(state.copyWith(status: ProfileSetupStatus.success));
},
onError: (String errorKey) => state.copyWith(
status: ProfileSetupStatus.failure,
errorMessage: errorKey,
),
);
}
Future<void> _onLocationQueryChanged(
@@ -116,6 +118,8 @@ class ProfileSetupBloc extends Bloc<ProfileSetupEvent, ProfileSetupState> {
return;
}
// For search, we might want to handle errors silently or distinctively
// Using simple try-catch here as it's a search-as-you-type feature where error dialogs are intrusive
try {
final results = await _searchCities(event.query);
emit(state.copyWith(locationSuggestions: results));
@@ -132,3 +136,4 @@ class ProfileSetupBloc extends Bloc<ProfileSetupEvent, ProfileSetupState> {
emit(state.copyWith(locationSuggestions: []));
}
}