feat: Refactor code structure and optimize performance across multiple modules

This commit is contained in:
Achintha Isuru
2025-11-17 23:29:28 -05:00
parent 831570f2e0
commit a64cbd9edf
1508 changed files with 105319 additions and 0 deletions

View File

@@ -0,0 +1,151 @@
import 'dart:developer';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:krow/core/application/common/validators/email_validator.dart';
import 'package:krow/core/application/di/injectable.dart';
import 'package:krow/core/data/enums/state_status.dart';
import 'package:krow/core/data/models/client/client.dart';
import 'package:krow/features/profile/data/profile_repository.dart';
part 'personal_info_event.dart';
part 'personal_info_state.dart';
class PersonalInfoBloc extends Bloc<PersonalInfoEvent, PersonalInfoState> {
PersonalInfoBloc() : super(const PersonalInfoState()) {
on<InitializeProfileInfoEvent>(_onInitializeProfileInfoEvent);
on<UpdateProfileImage>(_onUpdateProfileImage);
on<UpdateFirstName>(_onUpdateFirstName);
on<UpdateLastName>(_onUpdateLastName);
on<UpdateEmail>(_onUpdateEmail);
on<UpdatePhoneNumber>(_onUpdatePhoneNumber);
on<SaveProfileChanges>(_onSaveProfileChanges);
on<DeactivateProfile>(_onDeactivateProfile);
}
Future<void> _onInitializeProfileInfoEvent(
InitializeProfileInfoEvent event,
Emitter<PersonalInfoState> emit,
) async {
emit(
state.copyWith(
status: StateStatus.idle,
),
);
await for (final currentProfileData
in getIt<ClientProfileRepository>().getPersonalInfo()) {
try {
emit(
state.copyWith(
firstName: currentProfileData.firstName,
lastName: currentProfileData.lastName,
email: currentProfileData.authInfo?.email,
profileImageUrl: currentProfileData.avatar,
phoneNumber: currentProfileData.authInfo?.phone,
isUpdateReceived: true,
status: StateStatus.idle,
),
);
} catch (except) {
log(except.toString());
} finally {
emit(state.copyWith(isUpdateReceived: false));
}
}
if (state.status == StateStatus.loading) {
emit(state.copyWith(status: StateStatus.idle));
}
}
void _onUpdateProfileImage(
UpdateProfileImage event,
Emitter<PersonalInfoState> emit,
) {
emit(state.copyWith(profileImagePath: event.imagePath));
}
void _onUpdateFirstName(
UpdateFirstName event,
Emitter<PersonalInfoState> emit,
) {
emit(state.copyWith(firstName: event.firstName));
}
void _onUpdateLastName(
UpdateLastName event,
Emitter<PersonalInfoState> emit,
) {
emit(state.copyWith(lastName: event.lastName));
}
void _onUpdateEmail(
UpdateEmail event,
Emitter<PersonalInfoState> emit,
) {
final error = EmailValidator.validate(event.email);
emit(
state.copyWith(
email: event.email,
emailValidationError: error ?? '',
),
);
}
void _onUpdatePhoneNumber(
UpdatePhoneNumber event,
Emitter<PersonalInfoState> emit,
) {
emit(state.copyWith(phoneNumber: event.phoneNumber));
}
Future<void> _onSaveProfileChanges(
SaveProfileChanges event,
Emitter<PersonalInfoState> emit,
) async {
if (!state.isValid) {
emit(state.copyWith(status: StateStatus.error));
return;
}
emit(state.copyWith(status: StateStatus.loading));
ClientModel? response;
try {
response = await getIt<ClientProfileRepository>().updatePersonalInfo(
firstName: state.firstName,
lastName: state.lastName,
phone: state.phoneNumber,
avatarPath: state.profileImagePath,
);
} finally {
emit(
state.copyWith(
status: response != null ? StateStatus.success : StateStatus.idle,
),
);
}
}
Future<void> _onDeactivateProfile(
DeactivateProfile event,
Emitter<PersonalInfoState> emit,
) async {
emit(state.copyWith(status: StateStatus.loading));
try {
await getIt<ClientProfileRepository>().deactivateProfile();
} finally {
emit(state.copyWith(status: StateStatus.idle, deleted: true));
}
}
}

View File

@@ -0,0 +1,42 @@
part of 'personal_info_bloc.dart';
@immutable
sealed class PersonalInfoEvent {}
class InitializeProfileInfoEvent extends PersonalInfoEvent {
InitializeProfileInfoEvent();
}
class UpdateProfileImage extends PersonalInfoEvent {
UpdateProfileImage(this.imagePath);
final String imagePath;
}
class UpdateFirstName extends PersonalInfoEvent {
UpdateFirstName(this.firstName);
final String firstName;
}
class UpdateLastName extends PersonalInfoEvent {
UpdateLastName(this.lastName);
final String lastName;
}
class UpdateEmail extends PersonalInfoEvent {
UpdateEmail(this.email);
final String email;
}
class UpdatePhoneNumber extends PersonalInfoEvent {
UpdatePhoneNumber(this.phoneNumber);
final String phoneNumber;
}
class SaveProfileChanges extends PersonalInfoEvent {}
class DeactivateProfile extends PersonalInfoEvent {}

View File

@@ -0,0 +1,71 @@
part of 'personal_info_bloc.dart';
@immutable
class PersonalInfoState {
const PersonalInfoState({
this.firstName = '',
this.lastName = '',
this.email = '',
this.phoneNumber = '',
this.profileImageUrl,
this.profileImagePath,
this.isUpdateReceived = false,
this.status = StateStatus.idle,
this.emailValidationError = '',
this.deleted = false
});
final String firstName;
final String lastName;
final String email;
final String phoneNumber;
final String? profileImageUrl;
final String? profileImagePath;
final bool isUpdateReceived;
final StateStatus status;
final String emailValidationError;
final bool deleted;
PersonalInfoState copyWith({
String? firstName,
String? lastName,
String? email,
String? phoneNumber,
String? profileImageUrl,
String? profileImagePath,
bool? isUpdateReceived,
StateStatus? status,
String? emailValidationError,
bool? deleted,
}) {
return PersonalInfoState(
firstName: firstName ?? this.firstName,
lastName: lastName ?? this.lastName,
email: email ?? this.email,
phoneNumber: phoneNumber ?? this.phoneNumber,
profileImagePath: profileImagePath ?? this.profileImagePath,
profileImageUrl: profileImageUrl ?? this.profileImageUrl,
isUpdateReceived: isUpdateReceived ?? this.isUpdateReceived,
status: status ?? this.status,
deleted: deleted ?? this.deleted,
emailValidationError: emailValidationError ?? this.emailValidationError,
);
}
bool get isFilled {
return firstName.isNotEmpty && lastName.isNotEmpty && email.isNotEmpty;
// Phone should not be validated on initial profile setup
//(!isInEditMode || phoneNumber.isNotEmpty) &&
//photo is optional
// (profileImagePath != null || profileImageUrl != null);
}
bool get isValid {
return firstName.isNotEmpty &&
lastName.isNotEmpty &&
emailValidationError.isEmpty &&
// Phone should not be validated on initial profile setup
//(!isInEditMode || phoneNumber.isNotEmpty) &&
(profileImagePath != null || profileImageUrl != null);
}
}

View File

@@ -0,0 +1,45 @@
import 'dart:developer';
import 'package:injectable/injectable.dart';
import 'package:krow/core/data/models/client/client.dart';
import 'package:krow/features/profile/data/profile_api_source.dart';
import 'package:krow/features/profile/data/profile_repository.dart';
@Singleton(as: ClientProfileRepository)
class ClientProfileRepositoryImpl implements ClientProfileRepository {
ClientProfileRepositoryImpl({
required ClientProfileApiProvider apiProvider,
}) : _apiProvider = apiProvider;
final ClientProfileApiProvider _apiProvider;
@override
Stream<ClientModel> getPersonalInfo() {
return _apiProvider.getMeWithCache();
}
@override
Future<ClientModel> updatePersonalInfo({
required String firstName,
required String lastName,
required String phone,
String? avatarPath,
}) {
try {
return _apiProvider.updatePersonalInfo(
firstName: firstName,
lastName: lastName,
phone: phone,
avatarPath: avatarPath,
);
} catch (exception) {
log((exception as Error).stackTrace.toString());
rethrow;
}
}
@override
Future<void> deactivateProfile() {
return _apiProvider.deactivateClientProfile();
}
}