your-name db71578ded feat: Improves data synchronization and connectivity UI
Implements automatic synchronization of unsynced local reception data (move line quantities) to the backend before fetching new receptions. This ensures local changes are pushed when connectivity is available.

Adds a pull-to-refresh mechanism on the reception page, allowing users to manually refresh the list of receptions.

Integrates an offline indicator in the main app bar, providing immediate visual feedback on the application's network connectivity status.
2025-07-31 04:00:06 +03:00

125 lines
4.9 KiB
Dart

import 'package:e_scan/backend/objectbox/entities/stock_picking/stock_picking_record_entity.dart';
import 'package:e_scan/components/components.dart';
import 'package:e_scan/pages/operation/reception/reception_page_model.dart';
import 'package:e_scan/router/go_secure_router_builder.dart';
import 'package:e_scan/themes/app_theme.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter/material.dart';
class ReceptionPage extends ConsumerStatefulWidget {
const ReceptionPage({super.key});
@override
ConsumerState<ReceptionPage> createState() => _ReceptionPageState();
}
class _ReceptionPageState extends ConsumerState<ReceptionPage> {
final globalKey = GlobalKey<ScaffoldState>();
@override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) {
ref.read(receptionPageModelProvider.notifier).getUserConnected();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppTheme.of(context).primaryBackground,
key: globalKey,
drawer: DrawerComponent(isOperationExpanded: true),
appBar: MainAppbarComponent(
scaffoledKey: globalKey,
title: "Réceptions",
subTitle: "Opérations d'Entrepôt",
),
body: RefreshIndicator(
color: AppTheme.of(context).white,
backgroundColor: AppTheme.of(context).primary,
onRefresh: () async {
await ref
.read(receptionPageModelProvider.notifier)
.getAllReceptions();
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: ListView(
children: [
const SizedBox(height: 16),
QuickActionComponent(
onTapAdd: () {},
onTapScan: () {},
onTapSearch: () {},
),
const SizedBox(height: 16),
Consumer(
builder: (_, WidgetRef ref, _) {
final state = ref.watch(receptionPageModelProvider);
if (state.loadingReceptions) {
return Center(child: LoadingProgressComponent());
}
return Column(
spacing: 10,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Text(
// 'Réceptions',
// style: AppTheme.of(
// context,
// ).bodyMedium.copyWith(fontWeight: FontWeight.bold),
// ),
state.receptions.isEmpty == true
? Text('No data')
: ListView.builder(
physics: NeverScrollableScrollPhysics(),
primary: true,
shrinkWrap: true,
itemCount: state.receptions.length,
itemBuilder: (context, index) {
final reception = state.receptions[index];
return GestureDetector(
onTap: () {
final id = reception.id;
ReceptionDetailsRoute(
receptionId: id,
).push(context);
},
child: StockPickingCard(
synchronized:
reception.synchronized == true,
margin: EdgeInsets.symmetric(
horizontal: 5,
vertical: 5,
),
isDone: reception.isDone == true,
reference: reception.name ?? '',
from: reception
.locationId
.target
?.completeName,
to: reception
.locationDestId
.target
?.completeName,
contact:
reception.partnerId.target?.displayName,
origin: reception.origin,
status: reception.state,
),
);
},
),
],
);
},
),
],
),
),
),
);
}
}