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,219 @@
import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:gap/gap.dart';
import 'package:image_picker/image_picker.dart';
import 'package:krow/core/presentation/gen/assets.gen.dart';
import 'package:krow/core/presentation/styles/kw_box_decorations.dart';
import 'package:krow/core/presentation/styles/kw_text_styles.dart';
import 'package:krow/core/presentation/styles/theme.dart';
import 'package:krow/core/presentation/widgets/scroll_layout_helper.dart';
import 'package:krow/core/presentation/widgets/ui_kit/kw_app_bar.dart';
import 'package:krow/core/presentation/widgets/ui_kit/kw_button.dart';
import 'package:krow/core/presentation/widgets/uploud_image_card.dart';
import 'package:krow/features/profile/certificates/data/models/staff_certificate.dart';
import 'package:krow/features/profile/certificates/domain/bloc/certificates_bloc.dart';
import 'package:krow/features/profile/certificates/domain/bloc/certificates_event.dart';
import 'package:krow/features/profile/certificates/domain/bloc/certificates_state.dart';
import 'package:krow/features/profile/certificates/presentation/screen/certificates_upload_dialog.dart';
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
@RoutePage()
class CertificatesScreen extends StatelessWidget implements AutoRouteWrapper {
const CertificatesScreen({super.key});
@override
Widget wrappedRoute(BuildContext context) {
return BlocProvider(
create: (_) => CertificatesBloc()..add(CertificatesEventFetch()),
child: this,
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: KwAppBar(
titleText: 'certificates'.tr(),
),
body: BlocConsumer<CertificatesBloc, CertificatesState>(
listener: (context, state) {
if (state.success) {
context.router.maybePop();
}
},
builder: (context, state) {
return ModalProgressHUD(
inAsyncCall: state.loading,
child: ScrollLayoutHelper(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16),
upperWidget: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'please_indicate_certificates'.tr(),
style: AppTextStyles.bodyTinyMed
.copyWith(color: AppColors.blackGray),
),
if (state.showError) _buildErrorMessage(),
const Gap(24),
_buildUploadProofItems(
context,
state.certificatesItems,
state.showError,
),
],
),
lowerWidget: KwButton.primary(
label: 'confirm'.tr(),
onPressed: () {
BlocProvider.of<CertificatesBloc>(context)
.add(CertificatesEventSubmit());
}),
),
);
},
),
);
}
_buildUploadProofItems(
context,
List<CertificatesViewModel> items,
bool showError,
) {
return Column(
children: items.map(
(item) {
Color? statusColor = _getStatusColor(showError, item);
return UploadImageCard(
title: item.title,
onSelectImage: () {
ImagePicker()
.pickImage(source: ImageSource.gallery)
.then((value) {
if (value != null) {
_showSelectCertificateDialog(context, item, value.path);
}
});
},
onDeleteTap: () {
BlocProvider.of<CertificatesBloc>(context)
.add(CertificatesEventDelete(item));
},
onTap: () {},
imageUrl: item.imageUrl,
inUploading: item.uploading,
statusColor: statusColor,
message: showError && item.imageUrl == null
? 'availability_requires_confirmation'.tr()
: item.status == null
? 'supported_format'.tr()
: (item.status!.name[0].toUpperCase() +
item.status!.name.substring(1).toLowerCase()),
hasError: showError,
padding: const EdgeInsets.only(bottom: 8),
child: _buildExpirationRow(item),
);
},
).toList(),
);
}
Color? _getStatusColor(bool showError, CertificatesViewModel item) {
var statusColor = (showError && item.status == null) ||
item.status == CertificateStatus.declined
? AppColors.statusError
: item.status == CertificateStatus.verified
? AppColors.statusSuccess
: item.status == CertificateStatus.pending
? AppColors.primaryBlue
: null;
return statusColor;
}
Container _buildErrorMessage() {
return Container(
margin: const EdgeInsets.only(top: 12),
padding: const EdgeInsets.all(8),
decoration: KwBoxDecorations.primaryLight8,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: 28,
width: 28,
decoration: const BoxDecoration(
shape: BoxShape.circle, color: AppColors.tintRed),
child: Center(
child: Assets.images.icons.alertCircle.svg(),
),
),
const Gap(8),
Expanded(
child: Text(
'listed_certificates_mandatory'.tr(),
style: AppTextStyles.bodyTinyMed
.copyWith(color: AppColors.statusError),
),
),
],
),
);
}
Widget _buildExpirationRow(CertificatesViewModel item) {
var bgColor = item.isExpired
? AppColors.tintRed
: item.expireSoon()
? AppColors.tintYellow
: AppColors.tintGray;
var textColor = item.isExpired
? AppColors.statusError
: item.expireSoon()
? AppColors.statusWarningBody
: null;
return Container(
margin: const EdgeInsets.only(top: 6, right: 4),
decoration: BoxDecoration(
color: AppColors.grayWhite,
borderRadius: BorderRadius.circular(4),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
padding:
const EdgeInsets.only(left: 6, right: 6, top: 3, bottom: 5),
decoration: BoxDecoration(
color: bgColor, borderRadius: BorderRadius.circular(4)),
child: Text(
'${'expiration_date'.tr()} ',
style: AppTextStyles.bodyTinyReg.copyWith(color: textColor),
)),
const Gap(7),
if (item.expirationDate != null)
Text(
item.getExpirationInfo(),
style: AppTextStyles.bodyTinyMed
.copyWith(color: textColor ?? AppColors.blackGray),
),
],
),
);
}
void _showSelectCertificateDialog(
context, CertificatesViewModel item, imagePath) {
CertificatesUploadDialog.show(context, imagePath).then((expireDate) {
if (expireDate != null) {
BlocProvider.of<CertificatesBloc>(context).add(CertificatesEventUpload(
item: item, path: imagePath, expirationDate: expireDate));
}
});
}
}

View File

@@ -0,0 +1,143 @@
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:krow/core/application/common/text_formatters/expiration_date_formatter.dart';
import 'package:krow/core/application/common/validators/certificate_date_validator.dart';
import 'package:krow/core/presentation/gen/assets.gen.dart';
import 'package:krow/core/presentation/styles/kw_text_styles.dart';
import 'package:krow/core/presentation/styles/theme.dart';
import 'package:krow/core/presentation/widgets/ui_kit/kw_button.dart';
import 'package:krow/core/presentation/widgets/ui_kit/kw_input.dart';
class CertificatesUploadDialog extends StatefulWidget {
final String path;
const CertificatesUploadDialog({
super.key,
required this.path,
});
@override
State<CertificatesUploadDialog> createState() =>
_CertificatesUploadDialogState();
static Future<String?> show(BuildContext context, String path) {
return showDialog<String?>(
context: context,
builder: (BuildContext context) {
return CertificatesUploadDialog(
path: path,
);
},
);
}
}
class _CertificatesUploadDialogState extends State<CertificatesUploadDialog> {
final TextEditingController expiryDateController = TextEditingController();
String? inputError;
@override
void initState() {
super.initState();
expiryDateController.addListener(() {
if(expiryDateController.text.length == 10) {
inputError =
CertificateDateValidator.validate(expiryDateController.text);
}else{
inputError = null;
}
setState(() {});
});
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Center(
child: Container(
constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.9),
decoration: BoxDecoration(
color: AppColors.grayWhite,
borderRadius: BorderRadius.circular(16),
),
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
..._buildDialogTitle(context),
Material(
type: MaterialType.transparency,
child: KwTextInput(
title: 'expiry_date_1'.tr(),
hintText: 'enter_certificate_expiry_date'.tr(),
controller: expiryDateController,
maxLength: 10,
inputFormatters: [DateTextFormatter()],
keyboardType: TextInputType.datetime,
helperText: inputError,
showError: inputError != null,
),
),
const Gap(12),
_buildImage(context),
const Gap(24),
KwButton.primary(
label: 'save_certificate'.tr(),
disabled: expiryDateController.text.length != 10 || inputError != null,
onPressed: () {
Navigator.of(context).pop(expiryDateController.text);
},
),
],
),
),
),
),
),
);
}
ClipRRect _buildImage(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.circular(16),
child: Image.file(
File(widget.path),
width: MediaQuery.of(context).size.width - 80,
fit: BoxFit.contain,
),
);
}
List<Widget> _buildDialogTitle(BuildContext context) {
return [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'add_certificate_expiry_date'.tr(),
style: AppTextStyles.bodyLargeMed,
),
GestureDetector(
onTap: () {
Navigator.of(context).pop();
},
child: Assets.images.icons.x.svg(),
),
],
),
const Gap(8),
Text(
'please_enter_expiry_date'.tr(),
style: AppTextStyles.bodySmallReg.copyWith(color: AppColors.blackGray),
),
const SizedBox(height: 24),
];
}
}