feat: autorefresh
This commit is contained in:
@@ -12,6 +12,11 @@ part 'order_loader_bloc.freezed.dart';
|
|||||||
@injectable
|
@injectable
|
||||||
class OrderLoaderBloc extends Bloc<OrderLoaderEvent, OrderLoaderState> {
|
class OrderLoaderBloc extends Bloc<OrderLoaderEvent, OrderLoaderState> {
|
||||||
final IOrderRepository _repository;
|
final IOrderRepository _repository;
|
||||||
|
|
||||||
|
int _fetchRequestId = 0;
|
||||||
|
int _summaryRequestId = 0;
|
||||||
|
bool _isLoadingMore = false;
|
||||||
|
|
||||||
OrderLoaderBloc(this._repository) : super(OrderLoaderState.initial()) {
|
OrderLoaderBloc(this._repository) : super(OrderLoaderState.initial()) {
|
||||||
on<OrderLoaderEvent>(_onOrderLoaderEvent);
|
on<OrderLoaderEvent>(_onOrderLoaderEvent);
|
||||||
}
|
}
|
||||||
@@ -34,19 +39,43 @@ class OrderLoaderBloc extends Bloc<OrderLoaderEvent, OrderLoaderState> {
|
|||||||
emit(state.copyWith(outletId: e.outletId));
|
emit(state.copyWith(outletId: e.outletId));
|
||||||
},
|
},
|
||||||
fetched: (e) async {
|
fetched: (e) async {
|
||||||
var newState = state;
|
|
||||||
|
|
||||||
if (e.isRefresh) {
|
if (e.isRefresh) {
|
||||||
newState = state.copyWith(isFetching: true);
|
_fetchRequestId++;
|
||||||
|
emit(state.copyWith(isFetching: true));
|
||||||
emit(newState);
|
} else if (state.isFetching || _isLoadingMore) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
newState = await _mapFetchedToState(state, isRefresh: e.isRefresh);
|
final requestId = _fetchRequestId;
|
||||||
|
_isLoadingMore = !e.isRefresh;
|
||||||
|
|
||||||
emit(newState);
|
try {
|
||||||
|
final result = await _mapFetchedToState(
|
||||||
|
state,
|
||||||
|
isRefresh: e.isRefresh,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Filter berubah selama request berjalan, buang hasil lama
|
||||||
|
if (requestId != _fetchRequestId) return;
|
||||||
|
|
||||||
|
// Hanya ambil field list, supaya status/filter/summary terbaru
|
||||||
|
// tidak tertimpa snapshot lama
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
orders: result.orders,
|
||||||
|
failureOptionOrder: result.failureOptionOrder,
|
||||||
|
page: result.page,
|
||||||
|
hasReachedMax: result.hasReachedMax,
|
||||||
|
isFetching: false,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
if (!e.isRefresh) _isLoadingMore = false;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
summaryFetched: (e) async {
|
summaryFetched: (e) async {
|
||||||
|
final requestId = ++_summaryRequestId;
|
||||||
|
|
||||||
emit(state.copyWith(isFetchingSummary: true));
|
emit(state.copyWith(isFetchingSummary: true));
|
||||||
|
|
||||||
final results = await Future.wait([
|
final results = await Future.wait([
|
||||||
@@ -63,6 +92,8 @@ class OrderLoaderBloc extends Bloc<OrderLoaderEvent, OrderLoaderState> {
|
|||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if (requestId != _summaryRequestId) return;
|
||||||
|
|
||||||
emit(
|
emit(
|
||||||
state.copyWith(
|
state.copyWith(
|
||||||
isFetchingSummary: false,
|
isFetchingSummary: false,
|
||||||
|
|||||||
+1
-1
@@ -234,7 +234,7 @@
|
|||||||
"@active": {},
|
"@active": {},
|
||||||
"inactive": "Tidak Aktif",
|
"inactive": "Tidak Aktif",
|
||||||
"@inactive": {},
|
"@inactive": {},
|
||||||
"total_amount": "Jumlah Total",
|
"total_amount": "Total",
|
||||||
"@total_amount": {},
|
"@total_amount": {},
|
||||||
"table": "Meja",
|
"table": "Meja",
|
||||||
"@table": {},
|
"@table": {},
|
||||||
|
|||||||
@@ -343,7 +343,7 @@ class AppLocalizationsId extends AppLocalizations {
|
|||||||
String get inactive => 'Tidak Aktif';
|
String get inactive => 'Tidak Aktif';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get total_amount => 'Jumlah Total';
|
String get total_amount => 'Total';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get table => 'Meja';
|
String get table => 'Meja';
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import '../../../common/theme/theme.dart';
|
|||||||
import '../../../injection.dart';
|
import '../../../injection.dart';
|
||||||
import '../../components/button/button.dart';
|
import '../../components/button/button.dart';
|
||||||
import '../../components/spacer/spacer.dart';
|
import '../../components/spacer/spacer.dart';
|
||||||
|
import '../../router/app_router.gr.dart';
|
||||||
import 'widgets/feature.dart';
|
import 'widgets/feature.dart';
|
||||||
import 'widgets/header.dart';
|
import 'widgets/header.dart';
|
||||||
import 'widgets/home_top_products.dart';
|
import 'widgets/home_top_products.dart';
|
||||||
@@ -53,6 +54,9 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
|||||||
late AnimationController _headerAnimationController;
|
late AnimationController _headerAnimationController;
|
||||||
late AnimationController _contentAnimationController;
|
late AnimationController _contentAnimationController;
|
||||||
|
|
||||||
|
TabsRouter? _tabsRouter;
|
||||||
|
bool _isActiveTab = true;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@@ -77,8 +81,29 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeDependencies() {
|
||||||
|
super.didChangeDependencies();
|
||||||
|
|
||||||
|
final tabsRouter = AutoTabsRouter.of(context);
|
||||||
|
if (_tabsRouter != tabsRouter) {
|
||||||
|
_tabsRouter?.removeListener(_onTabChanged);
|
||||||
|
_tabsRouter = tabsRouter..addListener(_onTabChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh setiap kali tab Home dibuka lagi dari bottom nav
|
||||||
|
void _onTabChanged() {
|
||||||
|
final isActiveTab = _tabsRouter?.current.name == HomeRoute.name;
|
||||||
|
|
||||||
|
if (isActiveTab && !_isActiveTab) _refreshAll(context);
|
||||||
|
|
||||||
|
_isActiveTab = isActiveTab;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
_tabsRouter?.removeListener(_onTabChanged);
|
||||||
_headerAnimationController.dispose();
|
_headerAnimationController.dispose();
|
||||||
_contentAnimationController.dispose();
|
_contentAnimationController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
@@ -88,6 +113,13 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
|||||||
context.read<HomeBloc>().add(HomeEvent.fetchedDashboard());
|
context.read<HomeBloc>().add(HomeEvent.fetchedDashboard());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _refreshAll(BuildContext context) {
|
||||||
|
_refetchDashboard(context);
|
||||||
|
context.read<ExclusiveSummaryLoaderBloc>().add(
|
||||||
|
const ExclusiveSummaryLoaderEvent.fetched(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocListener<SelectedOutletBloc, SelectedOutletState>(
|
return BlocListener<SelectedOutletBloc, SelectedOutletState>(
|
||||||
@@ -100,7 +132,7 @@ class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
|
|||||||
backgroundColor: AppColor.white,
|
backgroundColor: AppColor.white,
|
||||||
color: AppColor.primary,
|
color: AppColor.primary,
|
||||||
onRefresh: () {
|
onRefresh: () {
|
||||||
_refetchDashboard(context);
|
_refreshAll(context);
|
||||||
return Future.value();
|
return Future.value();
|
||||||
},
|
},
|
||||||
child: BlocBuilder<HomeBloc, HomeState>(
|
child: BlocBuilder<HomeBloc, HomeState>(
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ class _OrderPageState extends State<OrderPage> with TickerProviderStateMixin {
|
|||||||
late Animation<Offset> _slideAnimation;
|
late Animation<Offset> _slideAnimation;
|
||||||
final ScrollController _scrollController = ScrollController();
|
final ScrollController _scrollController = ScrollController();
|
||||||
|
|
||||||
|
TabsRouter? _tabsRouter;
|
||||||
|
bool _isActiveTab = true;
|
||||||
|
|
||||||
// Filter state
|
// Filter state
|
||||||
final List<String> filterOptions = ['All', 'Pending', 'Completed'];
|
final List<String> filterOptions = ['All', 'Pending', 'Completed'];
|
||||||
|
|
||||||
@@ -80,8 +83,33 @@ class _OrderPageState extends State<OrderPage> with TickerProviderStateMixin {
|
|||||||
_slideController.forward();
|
_slideController.forward();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeDependencies() {
|
||||||
|
super.didChangeDependencies();
|
||||||
|
|
||||||
|
final tabsRouter = AutoTabsRouter.of(context);
|
||||||
|
if (_tabsRouter != tabsRouter) {
|
||||||
|
_tabsRouter?.removeListener(_onTabChanged);
|
||||||
|
_tabsRouter = tabsRouter..addListener(_onTabChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh setiap kali tab Order dibuka lagi dari bottom nav
|
||||||
|
void _onTabChanged() {
|
||||||
|
final isActiveTab = _tabsRouter?.current.name == OrderRoute.name;
|
||||||
|
|
||||||
|
if (isActiveTab && !_isActiveTab) {
|
||||||
|
context.read<OrderLoaderBloc>()
|
||||||
|
..add(OrderLoaderEvent.fetched(isRefresh: true))
|
||||||
|
..add(const OrderLoaderEvent.summaryFetched());
|
||||||
|
}
|
||||||
|
|
||||||
|
_isActiveTab = isActiveTab;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
_tabsRouter?.removeListener(_onTabChanged);
|
||||||
_fadeController.dispose();
|
_fadeController.dispose();
|
||||||
_slideController.dispose();
|
_slideController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@ description: "A new Flutter project."
|
|||||||
|
|
||||||
publish_to: "none"
|
publish_to: "none"
|
||||||
|
|
||||||
version: 1.0.4+18
|
version: 1.0.4+19
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.8.1
|
sdk: ^3.8.1
|
||||||
|
|||||||
Reference in New Issue
Block a user