276 lines
9.3 KiB
Dart
276 lines
9.3 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_svg/svg.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:mobile_scanner/mobile_scanner.dart';
|
|
import 'package:seshat/domain/models/book.dart';
|
|
import 'package:seshat/routing/routes.dart';
|
|
import 'package:seshat/ui/add_page/view_model/add_view_model.dart';
|
|
import 'package:seshat/ui/add_page/widgets/form_popup.dart';
|
|
import 'package:seshat/ui/add_page/widgets/owner_popup.dart';
|
|
import 'package:seshat/ui/add_page/widgets/confirmation_popup.dart';
|
|
import 'package:seshat/ui/core/ui/navigation_bar.dart';
|
|
import 'package:seshat/ui/core/ui/await_loading.dart';
|
|
import 'package:seshat/utils/result.dart';
|
|
|
|
class AddPage extends StatefulWidget {
|
|
const AddPage({super.key, required this.viewModel});
|
|
|
|
final AddViewModel viewModel;
|
|
|
|
@override
|
|
State<AddPage> createState() => _AddPageState();
|
|
}
|
|
|
|
class _AddPageState extends State<AddPage> {
|
|
num? price;
|
|
final MobileScannerController controller = MobileScannerController(
|
|
formats: [BarcodeFormat.ean13],
|
|
detectionTimeoutMs: 1000,
|
|
);
|
|
|
|
@override
|
|
void dispose() {
|
|
controller.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = Theme.of(context);
|
|
// return Consumer<TabScreen>(
|
|
// builder: (context, screen, child) {
|
|
return Scaffold(
|
|
bottomNavigationBar: AppNavigationBar(startIndex: 1),
|
|
body: ListenableBuilder(
|
|
listenable: widget.viewModel,
|
|
builder: (context, child) => switch (widget.viewModel.isLoaded) {
|
|
false => AwaitLoading(),
|
|
true => switch (widget.viewModel.currentBal) {
|
|
null => Center(
|
|
child: SizedBox(
|
|
width: 300,
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
Text(
|
|
"Aucune bal n'est active.",
|
|
style: TextStyle(fontSize: 25),
|
|
textAlign: TextAlign.center,
|
|
),
|
|
SizedBox(height: 15),
|
|
Text(
|
|
"Vous devez créer puis activer une BAL pour pouvoir scanner des livres.",
|
|
textAlign: TextAlign.center,
|
|
),
|
|
SizedBox(height: 30),
|
|
ElevatedButton(
|
|
onPressed: () {
|
|
context.go(Routes.home);
|
|
},
|
|
child: Text("Gérer les BALs"),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
_ => Stack(
|
|
children: [
|
|
ColoredBox(color: Colors.black),
|
|
MobileScanner(
|
|
controller: controller,
|
|
onDetect: (barcodes) async {
|
|
if (widget.viewModel.currentOwner == null) {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: Text(
|
|
"Attention : vous devez choisir un·e propriétaire",
|
|
),
|
|
behavior: SnackBarBehavior.floating,
|
|
),
|
|
);
|
|
return;
|
|
}
|
|
|
|
void setPrice(num newPrice) async {
|
|
setState(() {
|
|
price = newPrice;
|
|
});
|
|
}
|
|
|
|
Result<Book> result = await widget.viewModel.scanBook(
|
|
barcodes,
|
|
);
|
|
|
|
switch (result) {
|
|
case Ok():
|
|
await _confirmationDialogBuilder(
|
|
context,
|
|
setPrice,
|
|
controller,
|
|
widget.viewModel,
|
|
result.value,
|
|
);
|
|
break;
|
|
case Error():
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(
|
|
content: Text("Erreur : ${result.error}"),
|
|
behavior: SnackBarBehavior.floating,
|
|
),
|
|
);
|
|
break;
|
|
}
|
|
},
|
|
),
|
|
SafeArea(
|
|
child: SingleChildScrollView(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
SizedBox(height: 5),
|
|
Center(
|
|
child: Card(
|
|
margin: EdgeInsets.symmetric(horizontal: 50),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
ListTile(
|
|
leading: Icon(Icons.person),
|
|
title: TextButton(
|
|
child: Text(
|
|
(widget.viewModel.currentOwner == null)
|
|
? "Aucun"
|
|
: "${widget.viewModel.currentOwner!.firstName} ${widget.viewModel.currentOwner!.lastName}",
|
|
),
|
|
onPressed: () => _ownerDialogBuilder(
|
|
context,
|
|
controller,
|
|
widget.viewModel,
|
|
),
|
|
),
|
|
),
|
|
ListTile(
|
|
leading: Icon(Icons.attach_money),
|
|
title: TextButton(
|
|
child: Text(
|
|
(widget.viewModel.askPrice)
|
|
? "Demander à chaque fois"
|
|
: "Prix libre toujours",
|
|
),
|
|
onPressed: () {
|
|
setState(() {
|
|
widget.viewModel.askPrice =
|
|
!widget.viewModel.askPrice;
|
|
});
|
|
},
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
Center(child: SvgPicture.asset('assets/scan-overlay.svg')),
|
|
SafeArea(
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.end,
|
|
children: [
|
|
Center(
|
|
child: TextButton(
|
|
style: ButtonStyle(
|
|
backgroundColor: WidgetStatePropertyAll(
|
|
theme.cardColor,
|
|
),
|
|
),
|
|
onPressed: () => _formDialogBuilder(
|
|
context,
|
|
controller,
|
|
widget.viewModel,
|
|
),
|
|
child: Text("Enregistrer manuellement"),
|
|
),
|
|
),
|
|
SizedBox(height: 5),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
},
|
|
},
|
|
),
|
|
);
|
|
// },
|
|
// );
|
|
}
|
|
}
|
|
|
|
Future<void> _confirmationDialogBuilder(
|
|
BuildContext context,
|
|
Function(num) setPrice,
|
|
MobileScannerController controller,
|
|
AddViewModel viewModel,
|
|
Book book,
|
|
) {
|
|
controller.stop();
|
|
|
|
void exitPopup(BuildContext localContext) {
|
|
Navigator.of(localContext).pop();
|
|
controller.start();
|
|
}
|
|
|
|
return showDialog(
|
|
context: context,
|
|
barrierDismissible: false,
|
|
builder: (context) => ConfirmationPopup(
|
|
exitPopup: exitPopup,
|
|
setPrice: setPrice,
|
|
viewModel: viewModel,
|
|
book: book,
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> _formDialogBuilder(
|
|
BuildContext context,
|
|
MobileScannerController controller,
|
|
AddViewModel viewModel,
|
|
) {
|
|
controller.stop();
|
|
|
|
void exitPopup(BuildContext localContext) {
|
|
Navigator.of(localContext).pop();
|
|
controller.start();
|
|
}
|
|
|
|
return showDialog(
|
|
context: context,
|
|
barrierDismissible: false,
|
|
builder: (context) => FormPopup(viewModel: viewModel, exitPopup: exitPopup),
|
|
);
|
|
}
|
|
|
|
Future<void> _ownerDialogBuilder(
|
|
BuildContext context,
|
|
MobileScannerController controller,
|
|
AddViewModel viewModel,
|
|
) {
|
|
controller.stop();
|
|
|
|
void onPressAccept(BuildContext localContext) {
|
|
Navigator.of(localContext).pop();
|
|
controller.start();
|
|
}
|
|
|
|
return showDialog(
|
|
context: context,
|
|
barrierDismissible: false,
|
|
builder: (context) =>
|
|
OwnerPopup(viewModel: viewModel, onPressAccept: onPressAccept),
|
|
);
|
|
}
|