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,4 +1,5 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:krow_core/core.dart';
import '../../domain/usecases/get_profile_usecase.dart';
import '../../domain/usecases/sign_out_usecase.dart';
import 'profile_state.dart';
@@ -6,15 +7,14 @@ import 'profile_state.dart';
/// Cubit for managing the Profile feature state.
///
/// Handles loading profile data and user sign-out actions.
class ProfileCubit extends Cubit<ProfileState> {
class ProfileCubit extends Cubit<ProfileState>
with BlocErrorHandler<ProfileState> {
final GetProfileUseCase _getProfileUseCase;
final SignOutUseCase _signOutUseCase;
/// Creates a [ProfileCubit] with the required use cases.
ProfileCubit(
this._getProfileUseCase,
this._signOutUseCase,
) : super(const ProfileState());
ProfileCubit(this._getProfileUseCase, this._signOutUseCase)
: super(const ProfileState());
/// Loads the staff member's profile.
///
@@ -24,18 +24,16 @@ class ProfileCubit extends Cubit<ProfileState> {
Future<void> loadProfile() async {
emit(state.copyWith(status: ProfileStatus.loading));
try {
final profile = await _getProfileUseCase();
emit(state.copyWith(
status: ProfileStatus.loaded,
profile: profile,
));
} catch (e) {
emit(state.copyWith(
status: ProfileStatus.error,
errorMessage: e.toString(),
));
}
await handleError(
emit: emit,
action: () async {
final profile = await _getProfileUseCase();
emit(state.copyWith(status: ProfileStatus.loaded, profile: profile));
},
onError:
(String errorKey) =>
state.copyWith(status: ProfileStatus.error, errorMessage: errorKey),
);
}
/// Signs out the current user.
@@ -49,12 +47,21 @@ class ProfileCubit extends Cubit<ProfileState> {
emit(state.copyWith(status: ProfileStatus.loading));
try {
await _signOutUseCase();
emit(state.copyWith(status: ProfileStatus.signedOut));
} catch (e) {
// Error handling can be added here if needed
// For now, we let the navigation happen regardless
}
await handleError(
emit: emit,
action: () async {
await _signOutUseCase();
emit(state.copyWith(status: ProfileStatus.signedOut));
},
onError: (String _) {
// For sign out errors, we might want to just proceed or show error
// Current implementation was silent catch, let's keep it robust but consistent
// If we want to force navigation even on error, we would do it here
// But usually handleError emits the error state.
// Let's stick to standard error reporting for now.
return state.copyWith(status: ProfileStatus.error);
},
);
}
}

View File

@@ -14,7 +14,9 @@ import '../widgets/profile_menu_item.dart';
import '../widgets/profile_header.dart';
import '../widgets/reliability_score_bar.dart';
import '../widgets/reliability_stats_card.dart';
import '../widgets/reliability_stats_card.dart';
import '../widgets/section_title.dart';
import '../widgets/language_selector_bottom_sheet.dart';
/// The main Staff Profile page.
///
@@ -178,6 +180,25 @@ class StaffProfilePage extends StatelessWidget {
],
),
const SizedBox(height: UiConstants.space6),
SectionTitle(
i18n.header.title.contains("Perfil") ? "Ajustes" : "Settings",
),
ProfileMenuGrid(
crossAxisCount: 3,
children: [
ProfileMenuItem(
icon: UiIcons.globe,
label: i18n.header.title.contains("Perfil") ? "Idioma" : "Language",
onTap: () {
showModalBottomSheet(
context: context,
builder: (context) => const LanguageSelectorBottomSheet(),
);
},
),
],
),
const SizedBox(height: UiConstants.space6),
LogoutButton(
onTap: () => _onSignOut(cubit, state),
),

View File

@@ -0,0 +1,106 @@
import 'package:core_localization/core_localization.dart';
import 'package:design_system/design_system.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_modular/flutter_modular.dart';
/// A bottom sheet that allows the user to select their preferred language.
///
/// Displays options for English and Spanish, and updates the application's
/// locale via the [LocaleBloc].
class LanguageSelectorBottomSheet extends StatelessWidget {
/// Creates a [LanguageSelectorBottomSheet].
const LanguageSelectorBottomSheet({super.key});
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(UiConstants.space6),
decoration: BoxDecoration(
color: UiColors.background,
borderRadius: BorderRadius.vertical(top: Radius.circular(UiConstants.radiusBase)),
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
t.settings.change_language,
style: UiTypography.headline4m,
textAlign: TextAlign.center,
),
SizedBox(height: UiConstants.space6),
_buildLanguageOption(
context,
label: 'English',
locale: AppLocale.en,
),
SizedBox(height: UiConstants.space4),
_buildLanguageOption(
context,
label: 'Español',
locale: AppLocale.es,
),
SizedBox(height: UiConstants.space6),
],
),
);
}
Widget _buildLanguageOption(
BuildContext context, {
required String label,
required AppLocale locale,
}) {
// Check if this option is currently selected.
// We can use LocaleSettings.currentLocale for a quick check,
// or access the BLoC state if we wanted to be reactive to state changes here directly,
// but LocaleSettings is sufficient for the initial check.
final bool isSelected = LocaleSettings.currentLocale == locale;
return InkWell(
onTap: () {
// Dispatch the ChangeLocale event to the LocaleBloc
Modular.get<LocaleBloc>().add(ChangeLocale(locale.flutterLocale));
// Close the bottom sheet
Navigator.pop(context);
// Force a rebuild of the entire app to reflect locale change instantly if not handled by root widget
// (Usually handled by BlocBuilder at the root, but this ensures settings are updated)
},
borderRadius: BorderRadius.circular(UiConstants.radiusMdValue),
child: Container(
padding: EdgeInsets.symmetric(
vertical: UiConstants.space4,
horizontal: UiConstants.space4,
),
decoration: BoxDecoration(
color: isSelected ? UiColors.primary.withValues(alpha: 0.1) : UiColors.background,
borderRadius: BorderRadius.circular(UiConstants.radiusMdValue),
border: Border.all(
color: isSelected ? UiColors.primary : UiColors.border,
width: isSelected ? 2 : 1,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
label,
style: isSelected
? UiTypography.body1b.copyWith(color: UiColors.primary)
: UiTypography.body1r,
),
if (isSelected)
Icon(
UiIcons.check,
color: UiColors.primary,
size: 24.0,
),
],
),
),
);
}
}