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,70 @@
import 'package:bloc/bloc.dart';
import 'package:krow/core/application/clients/api/api_exception.dart';
import 'package:krow/core/application/di/injectable.dart';
import 'package:krow/features/invoice/data/models/invoice_decline_model.dart';
import 'package:krow/features/invoice/data/models/invoice_model.dart';
import 'package:krow/features/invoice/domain/invoices_repository.dart';
import 'package:meta/meta.dart';
part 'invoice_details_event.dart';
part 'invoice_details_state.dart';
class InvoiceDetailsBloc
extends Bloc<InvoiceDetailsEvent, InvoiceDetailsState> {
InvoiceDetailsBloc(InvoiceModel invoice)
: super(InvoiceDetailsState(invoiceModel: invoice)) {
on<InvoiceApproveEvent>(_onInvoiceApproveEvent);
on<InvoiceDisputeEvent>(_onInvoiceDisputeEvent);
}
void _onInvoiceApproveEvent(
InvoiceApproveEvent event, Emitter<InvoiceDetailsState> emit) async {
emit(state.copyWith(inLoading: true));
try {
await getIt<InvoicesRepository>().approveInvoice(
invoiceId: state.invoiceModel?.id ?? '',
);
emit(state.copyWith(inLoading: false, success: true));
return;
} catch (e) {
if (e is DisplayableException) {
emit(state.copyWith(inLoading: false, showErrorPopup: e.message));
return;
}
}
emit(state.copyWith(inLoading: false));
}
void _onInvoiceDisputeEvent(
InvoiceDisputeEvent event, Emitter<InvoiceDetailsState> emit) async {
emit(state.copyWith(inLoading: true));
try {
await getIt<InvoicesRepository>().disputeInvoice(
invoiceId: state.invoiceModel?.id ?? '',
reason: event.reason,
comment: event.comment,
);
emit(
state.copyWith(
inLoading: false,
invoiceModel: state.invoiceModel?.copyWith(
status: InvoiceStatus.disputed,
dispute: InvoiceDeclineModel(
id: '1',
reason: event.reason,
details: event.comment,
),
),
),
);
return;
} catch (e) {
print(e);
if (e is DisplayableException) {
emit(state.copyWith(inLoading: false, showErrorPopup: e.message));
return;
}
}
emit(state.copyWith(inLoading: false));
}
}

View File

@@ -0,0 +1,18 @@
part of 'invoice_details_bloc.dart';
@immutable
sealed class InvoiceDetailsEvent {}
class InvoiceApproveEvent extends InvoiceDetailsEvent {
InvoiceApproveEvent();
}
class InvoiceDisputeEvent extends InvoiceDetailsEvent {
final String reason;
final String comment;
InvoiceDisputeEvent({
required this.reason,
required this.comment,
});
}

View File

@@ -0,0 +1,20 @@
part of 'invoice_details_bloc.dart';
@immutable
class InvoiceDetailsState {
final String? showErrorPopup;
final bool inLoading;
final bool success;
final InvoiceModel? invoiceModel;
const InvoiceDetailsState( {this.showErrorPopup, this.inLoading = false,this.invoiceModel, this.success = false});
InvoiceDetailsState copyWith({String? showErrorPopup, bool? inLoading, InvoiceModel? invoiceModel, bool? success}) {
return InvoiceDetailsState(
showErrorPopup: showErrorPopup ?? this.showErrorPopup,
inLoading: inLoading ?? false,
success: success ?? this.success,
invoiceModel: invoiceModel ?? this.invoiceModel,
);
}
}

View File

@@ -0,0 +1,113 @@
import 'package:flutter/foundation.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:krow/core/application/di/injectable.dart';
import '../../invoice_entity.dart';
import '../../invoices_repository.dart';
import 'invoice_event.dart';
import 'invoice_state.dart';
class InvoiceBloc extends Bloc<InvoiceEvent, InvoicesState> {
var indexToStatus = <int, InvoiceStatusFilterType>{
0: InvoiceStatusFilterType.all,
1: InvoiceStatusFilterType.open,
2: InvoiceStatusFilterType.disputed,
3: InvoiceStatusFilterType.resolved,
4: InvoiceStatusFilterType.paid,
5: InvoiceStatusFilterType.overdue,
6: InvoiceStatusFilterType.verified,
};
InvoiceBloc()
: super(const InvoicesState(tabs: {
0: InvoiceTabState(items: [], inLoading: true),
1: InvoiceTabState(items: []),
2: InvoiceTabState(items: []),
3: InvoiceTabState(items: []),
4: InvoiceTabState(items: []),
5: InvoiceTabState(items: []),
6: InvoiceTabState(items: []),
})) {
on<InvoiceInitialEvent>(_onInitial);
on<InvoiceTabChangedEvent>(_onTabChanged);
on<LoadTabInvoiceEvent>(_onLoadTabItems);
on<LoadMoreInvoiceEvent>(_onLoadMoreTabItems);
getIt<InvoicesRepository>().statusStream.listen((event) {
add(LoadTabInvoiceEvent(status: event.index));
});
}
Future<void> _onInitial(InvoiceInitialEvent event, emit) async {
add(const LoadTabInvoiceEvent(status: 0));
}
Future<void> _onTabChanged(InvoiceTabChangedEvent event, emit) async {
emit(state.copyWith(tabIndex: event.tabIndex));
final currentTabState = state.tabs[event.tabIndex]!;
if (currentTabState.items.isEmpty && !currentTabState.inLoading) {
add(LoadTabInvoiceEvent(status: event.tabIndex));
}
}
Future<void> _onLoadTabItems(LoadTabInvoiceEvent event, emit) async {
await _fetchInvoices(event.status, null, emit);
}
Future<void> _onLoadMoreTabItems(LoadMoreInvoiceEvent event, emit) async {
final currentTabState = state.tabs[event.status]!;
if (!currentTabState.hasMoreItems || currentTabState.inLoading) return;
await _fetchInvoices(event.status, currentTabState.items, emit);
}
_fetchInvoices(
int tabIndex, List<InvoiceListEntity>? previousItems, emit) async {
if (previousItems != null && previousItems.lastOrNull?.cursor == null) {
return;
}
final currentTabState = state.tabs[tabIndex]!;
emit(state.copyWith(
tabs: {
...state.tabs,
tabIndex: currentTabState.copyWith(inLoading: true),
},
));
try {
var items = await getIt<InvoicesRepository>().getInvoices(
statusFilter: indexToStatus[tabIndex]!,
lastItemId: previousItems?.lastOrNull?.cursor,
);
// if(items.isNotEmpty){
// items = List.generate(20, (i)=>items[0]);
// }
emit(state.copyWith(
tabs: {
...state.tabs,
tabIndex: currentTabState.copyWith(
items: (previousItems ?? [])..addAll(items),
hasMoreItems: items.isNotEmpty,
inLoading: false,
),
},
));
} catch (e, s) {
debugPrint(e.toString());
debugPrint(s.toString());
emit(state.copyWith(
tabs: {
...state.tabs,
tabIndex: currentTabState.copyWith(inLoading: false),
},
));
}
}
@override
Future<void> close() {
getIt<InvoicesRepository>().dispose();
return super.close();
}
}

View File

@@ -0,0 +1,25 @@
sealed class InvoiceEvent {
const InvoiceEvent();
}
class InvoiceInitialEvent extends InvoiceEvent {
const InvoiceInitialEvent();
}
class InvoiceTabChangedEvent extends InvoiceEvent {
final int tabIndex;
const InvoiceTabChangedEvent({required this.tabIndex});
}
class LoadTabInvoiceEvent extends InvoiceEvent {
final int status;
const LoadTabInvoiceEvent({required this.status});
}
class LoadMoreInvoiceEvent extends InvoiceEvent {
final int status;
const LoadMoreInvoiceEvent({required this.status});
}

View File

@@ -0,0 +1,47 @@
import 'package:krow/features/invoice/domain/invoice_entity.dart';
class InvoicesState {
final bool inLoading;
final int tabIndex;
final Map<int, InvoiceTabState> tabs;
const InvoicesState(
{this.inLoading = false, this.tabIndex = 0, required this.tabs});
InvoicesState copyWith({
bool? inLoading,
int? tabIndex,
Map<int, InvoiceTabState>? tabs,
}) {
return InvoicesState(
inLoading: inLoading ?? this.inLoading,
tabIndex: tabIndex ?? this.tabIndex,
tabs: tabs ?? this.tabs,
);
}
}
class InvoiceTabState {
final List<InvoiceListEntity> items;
final bool inLoading;
final bool hasMoreItems;
const InvoiceTabState({
required this.items,
this.inLoading = false,
this.hasMoreItems = true,
});
InvoiceTabState copyWith({
List<InvoiceListEntity>? items,
bool? inLoading,
bool? hasMoreItems,
}) {
return InvoiceTabState(
items: items ?? this.items,
inLoading: inLoading ?? this.inLoading,
hasMoreItems: hasMoreItems ?? this.hasMoreItems,
);
}
}