PrinterFormBloc dan PrinterLoaderBloc di-provide sekali secara global, sementara lima tab pengaturan printer hidup bersamaan di dalam TabBarView dan semuanya membaca-menulis state yang sama. Karena created dan updated membangun entitas Printer sepenuhnya dari state itu (type, address, code, name, paper), tab yang terakhir menulis state akan menang, lalu tombol Simpan di tab mana pun menyimpan milik tab lain. Nilai awal state kebetulan type 'Bluetooth' — itu sebabnya printer kitchen tersimpan dengan alamat IP yang benar tapi tipe Bluetooth, dan cetakannya dikirim ke radio Bluetooth untuk mencari perangkat yang tidak pernah ada. Provider global dihapus karena tidak ada tempat lain yang memakainya. Catatan: ini mencegah kerusakan baru, tidak memulihkan baris yang sudah terlanjur salah di SQLite — konfigurasi kelima tab perlu disimpan ulang. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
88 lines
4.2 KiB
Dart
88 lines
4.2 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
|
|
import '../application/auth/auth_bloc.dart';
|
|
import '../application/auth/logout/logout_bloc.dart';
|
|
import '../application/category/category_loader/category_loader_bloc.dart';
|
|
import '../application/checkout/checkout_form/checkout_form_bloc.dart';
|
|
import '../application/customer/customer_loader/customer_loader_bloc.dart';
|
|
import '../application/order/order_form/order_form_bloc.dart';
|
|
import '../application/order/order_loader/order_loader_bloc.dart';
|
|
import '../application/outlet/outlet_loader/outlet_loader_bloc.dart';
|
|
import '../application/payment_method/payment_method_loader/payment_method_loader_bloc.dart';
|
|
import '../application/printer/bluetooth/bluetooth_connect/bluetooth_connect_bloc.dart';
|
|
import '../application/printer/bluetooth/bluetooth_loader/bluetooth_loader_bloc.dart';
|
|
import '../application/printer/print_struck/print_struck_bloc.dart';
|
|
import '../application/product/product_loader/product_loader_bloc.dart';
|
|
import '../application/sync/sync_setting/sync_setting_bloc.dart';
|
|
import '../application/table/table_form/table_form_bloc.dart';
|
|
import '../application/table/table_loader/table_loader_bloc.dart';
|
|
import '../application/void/void_form/void_form_bloc.dart';
|
|
import '../common/theme/theme.dart';
|
|
import '../common/constant/app_constant.dart';
|
|
import '../injection.dart';
|
|
import 'components/dialog/dialog.dart';
|
|
import 'router/app_router.dart';
|
|
import 'router/app_router_observer.dart';
|
|
|
|
class AppWidget extends StatefulWidget {
|
|
const AppWidget({super.key});
|
|
|
|
@override
|
|
State<AppWidget> createState() => _AppWidgetState();
|
|
}
|
|
|
|
class _AppWidgetState extends State<AppWidget> {
|
|
final _appRouter = getIt<AppRouter>();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return MultiBlocProvider(
|
|
providers: [
|
|
BlocProvider(create: (context) => getIt<AuthBloc>()),
|
|
BlocProvider(create: (context) => getIt<OutletLoaderBloc>()),
|
|
BlocProvider(create: (context) => getIt<CategoryLoaderBloc>()),
|
|
BlocProvider(create: (context) => getIt<ProductLoaderBloc>()),
|
|
BlocProvider(create: (context) => getIt<CheckoutFormBloc>()),
|
|
BlocProvider(create: (context) => getIt<TableLoaderBloc>()),
|
|
BlocProvider(create: (context) => getIt<TableFormBloc>()),
|
|
BlocProvider(create: (context) => getIt<PaymentMethodLoaderBloc>()),
|
|
BlocProvider(create: (context) => getIt<OrderFormBloc>()),
|
|
BlocProvider(create: (context) => getIt<OrderLoaderBloc>()),
|
|
BlocProvider(create: (context) => getIt<CustomerLoaderBloc>()),
|
|
BlocProvider(create: (context) => getIt<VoidFormBloc>()),
|
|
BlocProvider(create: (context) => getIt<BluetoothLoaderBloc>()),
|
|
BlocProvider(create: (context) => getIt<BluetoothConnectBloc>()),
|
|
// PrinterFormBloc dan PrinterLoaderBloc sengaja TIDAK global: tiap tab
|
|
// pengaturan printer memakai instance sendiri, lihat
|
|
// SettingPrinterSection.
|
|
BlocProvider(create: (context) => getIt<PrintStruckBloc>()),
|
|
BlocProvider(create: (context) => getIt<SyncSettingBloc>()),
|
|
BlocProvider(create: (context) => getIt<LogoutBloc>()),
|
|
],
|
|
child: MaterialApp.router(
|
|
debugShowCheckedModeBanner: false,
|
|
title: AppConstant.appName,
|
|
theme: ThemeApp.theme,
|
|
routerConfig: _appRouter.config(
|
|
navigatorObservers: () => <NavigatorObserver>[AppRouteObserver()],
|
|
),
|
|
// Satu listener untuk seluruh aplikasi: cetak bisa dipicu dari banyak
|
|
// halaman, dan `PrintStruckBloc` hidup di atas router jadi prosesnya
|
|
// tetap jalan walau kasir sudah pindah halaman.
|
|
builder: (context, child) => BlocListener<PrintStruckBloc, PrintStruckState>(
|
|
listenWhen: (previous, current) => previous.jobId != current.jobId,
|
|
listener: (_, __) {
|
|
// Dialog harus dibuka dari context di bawah Navigator, sementara
|
|
// builder ini berada di atasnya.
|
|
final navigatorContext = _appRouter.navigatorKey.currentContext;
|
|
if (navigatorContext == null) return;
|
|
showPrintProgressDialog(navigatorContext);
|
|
},
|
|
child: child ?? const SizedBox.shrink(),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|