feat: add a book by scanning
This commit is contained in:
parent
72fd0b66a9
commit
981dce5bfe
14 changed files with 264 additions and 59 deletions
|
|
@ -1,6 +1,8 @@
|
||||||
import "package:provider/provider.dart";
|
import "package:provider/provider.dart";
|
||||||
import "package:provider/single_child_widget.dart";
|
import "package:provider/single_child_widget.dart";
|
||||||
import "package:seshat/data/repositories/auth_repository.dart";
|
import "package:seshat/data/repositories/auth_repository.dart";
|
||||||
|
import "package:seshat/data/repositories/book_instance_repository.dart";
|
||||||
|
import "package:seshat/data/repositories/book_repository.dart";
|
||||||
|
|
||||||
import "package:seshat/data/repositories/owner_repository.dart";
|
import "package:seshat/data/repositories/owner_repository.dart";
|
||||||
import "package:seshat/data/services/api_client.dart";
|
import "package:seshat/data/services/api_client.dart";
|
||||||
|
|
@ -19,5 +21,9 @@ List<SingleChildWidget> get providers {
|
||||||
ChangeNotifierProvider(
|
ChangeNotifierProvider(
|
||||||
create: (context) => AuthRepository(authClient: context.read()),
|
create: (context) => AuthRepository(authClient: context.read()),
|
||||||
),
|
),
|
||||||
|
Provider(create: (context) => BookRepository(apiClient: context.read())),
|
||||||
|
Provider(
|
||||||
|
create: (context) => BookInstanceRepository(apiClient: context.read()),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1,22 @@
|
||||||
class BookInstanceRepository {}
|
import 'package:seshat/data/services/api_client.dart';
|
||||||
|
import 'package:seshat/domain/models/bal.dart';
|
||||||
|
import 'package:seshat/domain/models/book.dart';
|
||||||
|
import 'package:seshat/domain/models/book_instance.dart';
|
||||||
|
import 'package:seshat/domain/models/owner.dart';
|
||||||
|
import 'package:seshat/utils/result.dart';
|
||||||
|
|
||||||
|
class BookInstanceRepository {
|
||||||
|
BookInstanceRepository({required ApiClient apiClient})
|
||||||
|
: _apiClient = apiClient;
|
||||||
|
|
||||||
|
final ApiClient _apiClient;
|
||||||
|
|
||||||
|
Future<Result<BookInstance>> sendBook(
|
||||||
|
Book book,
|
||||||
|
Owner owner,
|
||||||
|
Bal bal,
|
||||||
|
double price,
|
||||||
|
) async {
|
||||||
|
return await _apiClient.sendBook(book, owner, bal, price);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1,13 @@
|
||||||
class BookRepository {}
|
import 'package:seshat/data/services/api_client.dart';
|
||||||
|
import 'package:seshat/domain/models/book.dart';
|
||||||
|
import 'package:seshat/utils/result.dart';
|
||||||
|
|
||||||
|
class BookRepository {
|
||||||
|
BookRepository({required ApiClient apiClient}) : _apiClient = apiClient;
|
||||||
|
|
||||||
|
final ApiClient _apiClient;
|
||||||
|
|
||||||
|
Future<Result<Book>> getBookByEAN(String ean) async {
|
||||||
|
return _apiClient.getBookByEAN(ean);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
import 'package:seshat/config/constants.dart';
|
import 'package:seshat/config/constants.dart';
|
||||||
|
import 'package:seshat/domain/models/bal.dart';
|
||||||
|
import 'package:seshat/domain/models/book.dart';
|
||||||
|
import 'package:seshat/domain/models/book_instance.dart';
|
||||||
import 'package:seshat/domain/models/owner.dart';
|
import 'package:seshat/domain/models/owner.dart';
|
||||||
import 'package:seshat/utils/command.dart';
|
import 'package:seshat/utils/command.dart';
|
||||||
import 'package:seshat/utils/result.dart';
|
import 'package:seshat/utils/result.dart';
|
||||||
|
|
@ -23,18 +27,101 @@ class ApiClient {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Map<String, String>> _getHeaders([
|
||||||
|
Map<String, String>? additionalHeaders,
|
||||||
|
]) async {
|
||||||
|
await _initStore();
|
||||||
|
final token = await _secureStorage!.read(key: "token");
|
||||||
|
final headers = {"Authorization": "Bearer $token", ...?additionalHeaders};
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ===================
|
||||||
|
* =====[ BOOKS ]=====
|
||||||
|
* ===================
|
||||||
|
*/
|
||||||
|
|
||||||
|
Future<Result<Book>> getBookByEAN(String ean) async {
|
||||||
|
final client = Client();
|
||||||
|
try {
|
||||||
|
final headers = await _getHeaders();
|
||||||
|
final response = await client.get(
|
||||||
|
Uri.parse("https://$apiBasePath/book/ean/$ean"),
|
||||||
|
headers: headers,
|
||||||
|
);
|
||||||
|
debugPrint("\n\n\n\nGOT : ${response.statusCode}\n\n\n\n");
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
debugPrint("\n\n\n\nWITH : ${response.body}\n\n\n\n");
|
||||||
|
final json = jsonDecode(response.body);
|
||||||
|
return Result.ok(Book.fromJSON(json));
|
||||||
|
} else {
|
||||||
|
debugPrintStack();
|
||||||
|
return Result.error(Exception("The book was not found"));
|
||||||
|
}
|
||||||
|
} catch (e, stackTrace) {
|
||||||
|
debugPrintStack(stackTrace: stackTrace);
|
||||||
|
return Result.error(Exception("API $e"));
|
||||||
|
} finally {
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* =============================
|
||||||
|
* =====[ BOOKS INSTANCES ]=====
|
||||||
|
* =============================
|
||||||
|
*/
|
||||||
|
|
||||||
|
Future<Result<BookInstance>> sendBook(
|
||||||
|
Book book,
|
||||||
|
Owner owner,
|
||||||
|
Bal bal,
|
||||||
|
double price,
|
||||||
|
) async {
|
||||||
|
final client = Client();
|
||||||
|
try {
|
||||||
|
final headers = await _getHeaders({"Content-Type": "application/json"});
|
||||||
|
final body = jsonEncode({
|
||||||
|
"bal_id": bal.id,
|
||||||
|
"book_id": book.id,
|
||||||
|
"owner_id": owner.id,
|
||||||
|
"price": price,
|
||||||
|
});
|
||||||
|
debugPrint("\n\n\n\nSENDING : ${body}\n\n\n\n");
|
||||||
|
final response = await client.post(
|
||||||
|
Uri.parse("https://$apiBasePath/book_instance"),
|
||||||
|
headers: headers,
|
||||||
|
body: body,
|
||||||
|
);
|
||||||
|
if (response.statusCode == 201) {
|
||||||
|
final json = jsonDecode(response.body);
|
||||||
|
debugPrint("\n\n\n\nRECEIVED : ${json}\n\n\n\n");
|
||||||
|
return Result.ok(BookInstance.fromJSON(json));
|
||||||
|
} else if (response.statusCode == 403) {
|
||||||
|
return Result.error(Exception("You don't own that book instance"));
|
||||||
|
} else {
|
||||||
|
return Result.error(Exception("Something wrong happened"));
|
||||||
|
}
|
||||||
|
} catch (e, stack) {
|
||||||
|
debugPrintStack(stackTrace: stack);
|
||||||
|
return Result.error(Exception(e));
|
||||||
|
} finally {
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ====================
|
* ====================
|
||||||
* =====[ OWNERS ]=====
|
* =====[ OWNERS ]=====
|
||||||
* ====================
|
* ====================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/// Call on `/owners` to get a list of all [Owner]s
|
||||||
Future<Result<List<Owner>>> getOwners() async {
|
Future<Result<List<Owner>>> getOwners() async {
|
||||||
final client = Client();
|
final client = Client();
|
||||||
try {
|
try {
|
||||||
await _initStore();
|
final headers = await _getHeaders();
|
||||||
final token = await _secureStorage!.read(key: "token");
|
|
||||||
final headers = {"Authorization": "Bearer $token"};
|
|
||||||
final response = await client.get(
|
final response = await client.get(
|
||||||
Uri.parse("https://$apiBasePath/owners"),
|
Uri.parse("https://$apiBasePath/owners"),
|
||||||
headers: headers,
|
headers: headers,
|
||||||
|
|
@ -54,6 +141,7 @@ class ApiClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds an owner to the database
|
||||||
Future<Result<Owner>> addOwner(
|
Future<Result<Owner>> addOwner(
|
||||||
String firstName,
|
String firstName,
|
||||||
String lastName,
|
String lastName,
|
||||||
|
|
@ -61,12 +149,7 @@ class ApiClient {
|
||||||
) async {
|
) async {
|
||||||
final client = Client();
|
final client = Client();
|
||||||
try {
|
try {
|
||||||
await _initStore();
|
final headers = await _getHeaders({"Content-Type": "application/json"});
|
||||||
final token = await _secureStorage!.read(key: "token");
|
|
||||||
final headers = {
|
|
||||||
"Authorization": "Bearer $token",
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
};
|
|
||||||
final body = {
|
final body = {
|
||||||
"first_name": firstName,
|
"first_name": firstName,
|
||||||
"last_name": lastName,
|
"last_name": lastName,
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ class AuthClient {
|
||||||
try {
|
try {
|
||||||
await _initStore();
|
await _initStore();
|
||||||
bool hasToken = await _secureStorage!.containsKey(key: "token");
|
bool hasToken = await _secureStorage!.containsKey(key: "token");
|
||||||
debugPrint("\n\n\n${hasToken == true} => HAS_TOKEN\n\n\n");
|
|
||||||
if (hasToken) {
|
if (hasToken) {
|
||||||
var token = await _secureStorage!.read(key: "token");
|
var token = await _secureStorage!.read(key: "token");
|
||||||
var url = Uri.parse("https://$apiBasePath/token-check");
|
var url = Uri.parse("https://$apiBasePath/token-check");
|
||||||
|
|
@ -29,9 +28,6 @@ class AuthClient {
|
||||||
headers: {"Content-Type": "application/json"},
|
headers: {"Content-Type": "application/json"},
|
||||||
body: jsonEncode({"token": token}),
|
body: jsonEncode({"token": token}),
|
||||||
);
|
);
|
||||||
debugPrint(
|
|
||||||
"\n\n\n${response.body is String} => ${response.body}\n\n\n",
|
|
||||||
);
|
|
||||||
|
|
||||||
if (response.body == "true") {
|
if (response.body == "true") {
|
||||||
return Result.ok(true);
|
return Result.ok(true);
|
||||||
|
|
@ -39,7 +35,6 @@ class AuthClient {
|
||||||
}
|
}
|
||||||
return Result.ok(false);
|
return Result.ok(false);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint(e.toString());
|
|
||||||
return Result.error(Exception(e));
|
return Result.error(Exception(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -67,8 +62,6 @@ class AuthClient {
|
||||||
return Result.error(Exception("Token creation error"));
|
return Result.error(Exception("Token creation error"));
|
||||||
}
|
}
|
||||||
} catch (e, stackTrace) {
|
} catch (e, stackTrace) {
|
||||||
debugPrint(e.toString());
|
|
||||||
debugPrintStack(stackTrace: stackTrace);
|
|
||||||
return Result.error(Exception(e));
|
return Result.error(Exception(e));
|
||||||
} finally {
|
} finally {
|
||||||
client.close();
|
client.close();
|
||||||
|
|
|
||||||
5
lib/domain/models/bal.dart
Normal file
5
lib/domain/models/bal.dart
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
class Bal {
|
||||||
|
Bal({required this.id});
|
||||||
|
|
||||||
|
int id;
|
||||||
|
}
|
||||||
|
|
@ -12,4 +12,12 @@ class Book {
|
||||||
String ean;
|
String ean;
|
||||||
int id;
|
int id;
|
||||||
String priceNew;
|
String priceNew;
|
||||||
|
|
||||||
|
factory Book.fromJSON(Map<String, dynamic> json) => Book(
|
||||||
|
author: json["author"],
|
||||||
|
ean: json["ean"],
|
||||||
|
id: json["id"],
|
||||||
|
priceNew: json["price_new"],
|
||||||
|
title: json["title"],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ class BookInstance {
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.ownerId,
|
required this.ownerId,
|
||||||
required this.price,
|
required this.price,
|
||||||
required this.status,
|
required this.available,
|
||||||
this.soldPrice,
|
this.soldPrice,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -15,14 +15,15 @@ class BookInstance {
|
||||||
int ownerId;
|
int ownerId;
|
||||||
double price;
|
double price;
|
||||||
double? soldPrice;
|
double? soldPrice;
|
||||||
bool status;
|
bool available;
|
||||||
|
|
||||||
factory BookInstance.fromJSON(Map<String, dynamic> json) => BookInstance(
|
factory BookInstance.fromJSON(Map<String, dynamic> json) => BookInstance(
|
||||||
balId: json["balId"],
|
balId: json["bal_id"],
|
||||||
bookId: json["bookId"],
|
bookId: json["book_id"],
|
||||||
id: json["id"],
|
id: json["id"],
|
||||||
ownerId: json["ownerId"],
|
ownerId: json["owner_id"],
|
||||||
price: json["price"],
|
price: json["price"],
|
||||||
status: json["status"],
|
available: json["available"],
|
||||||
|
soldPrice: json["sold_price"] ?? 0,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,11 @@ GoRouter router(AuthRepository authRepository) => GoRouter(
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: Routes.add,
|
path: Routes.add,
|
||||||
pageBuilder: (context, state) {
|
pageBuilder: (context, state) {
|
||||||
final viewModel = AddViewModel(ownerRepository: context.read());
|
final viewModel = AddViewModel(
|
||||||
|
ownerRepository: context.read(),
|
||||||
|
bookRepository: context.read(),
|
||||||
|
bookInstanceRepository: context.read(),
|
||||||
|
);
|
||||||
return NoTransitionPage(child: AddPage(viewModel: viewModel));
|
return NoTransitionPage(child: AddPage(viewModel: viewModel));
|
||||||
},
|
},
|
||||||
// routes: [
|
// routes: [
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,30 @@ import 'dart:async';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:mobile_scanner/mobile_scanner.dart';
|
import 'package:mobile_scanner/mobile_scanner.dart';
|
||||||
|
import 'package:seshat/data/repositories/book_instance_repository.dart';
|
||||||
|
import 'package:seshat/data/repositories/book_repository.dart';
|
||||||
import 'package:seshat/data/repositories/owner_repository.dart';
|
import 'package:seshat/data/repositories/owner_repository.dart';
|
||||||
|
import 'package:seshat/domain/models/bal.dart';
|
||||||
import 'package:seshat/domain/models/book.dart';
|
import 'package:seshat/domain/models/book.dart';
|
||||||
|
import 'package:seshat/domain/models/book_instance.dart';
|
||||||
import 'package:seshat/domain/models/owner.dart';
|
import 'package:seshat/domain/models/owner.dart';
|
||||||
import 'package:seshat/utils/command.dart';
|
import 'package:seshat/utils/command.dart';
|
||||||
import 'package:seshat/utils/result.dart';
|
import 'package:seshat/utils/result.dart';
|
||||||
|
|
||||||
class AddViewModel extends ChangeNotifier {
|
class AddViewModel extends ChangeNotifier {
|
||||||
AddViewModel({required OwnerRepository ownerRepository})
|
AddViewModel({
|
||||||
: _ownerRepository = ownerRepository {
|
required OwnerRepository ownerRepository,
|
||||||
|
required BookRepository bookRepository,
|
||||||
|
required BookInstanceRepository bookInstanceRepository,
|
||||||
|
}) : _ownerRepository = ownerRepository,
|
||||||
|
_bookRepository = bookRepository,
|
||||||
|
_bookInstanceRepository = bookInstanceRepository {
|
||||||
load = Command0(_load)..execute();
|
load = Command0(_load)..execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
final OwnerRepository _ownerRepository;
|
final OwnerRepository _ownerRepository;
|
||||||
|
final BookRepository _bookRepository;
|
||||||
|
final BookInstanceRepository _bookInstanceRepository;
|
||||||
late final StreamSubscription sub;
|
late final StreamSubscription sub;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -87,15 +98,18 @@ class AddViewModel extends ChangeNotifier {
|
||||||
/// Sends an api request with a [bacorde], then gets the [Book] that was
|
/// Sends an api request with a [bacorde], then gets the [Book] that was
|
||||||
/// either created or retrieved. Sens the [Book] back wrapped in a [Result].
|
/// either created or retrieved. Sens the [Book] back wrapped in a [Result].
|
||||||
Future<Result<Book>> scanBook(BarcodeCapture barcode) async {
|
Future<Result<Book>> scanBook(BarcodeCapture barcode) async {
|
||||||
return Result.ok(
|
var ean = barcode.barcodes.first.rawValue!;
|
||||||
Book(
|
var result = await _bookRepository.getBookByEAN(ean);
|
||||||
author: "Patrick K. Dewdney",
|
return result;
|
||||||
ean: barcode.barcodes.first.rawValue!,
|
}
|
||||||
id: 56,
|
|
||||||
priceNew: "50 EUR",
|
Future<Result<BookInstance>> sendBook(
|
||||||
title: "Les chiens et la charrue",
|
Book book,
|
||||||
),
|
Owner owner,
|
||||||
);
|
Bal bal,
|
||||||
|
double price,
|
||||||
|
) async {
|
||||||
|
return await _bookInstanceRepository.sendBook(book, owner, bal, price);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends an api request with
|
/// Sends an api request with
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,8 @@ class _AddPageState extends State<AddPage> {
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case Error():
|
case Error():
|
||||||
|
debugPrintStack();
|
||||||
|
debugPrint(result.error.toString());
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text("Erreur : ${result.error}"),
|
content: Text("Erreur : ${result.error}"),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
|
import 'dart:ffi';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:seshat/domain/models/bal.dart';
|
||||||
import 'package:seshat/domain/models/book.dart';
|
import 'package:seshat/domain/models/book.dart';
|
||||||
import 'package:seshat/ui/add_page/view_model/add_view_model.dart';
|
import 'package:seshat/ui/add_page/view_model/add_view_model.dart';
|
||||||
|
import 'package:seshat/utils/result.dart';
|
||||||
|
|
||||||
class ConfirmationPopup extends StatefulWidget {
|
class ConfirmationPopup extends StatefulWidget {
|
||||||
const ConfirmationPopup({
|
const ConfirmationPopup({
|
||||||
|
|
@ -22,7 +26,7 @@ class ConfirmationPopup extends StatefulWidget {
|
||||||
|
|
||||||
class _ConfirmationPopupState extends State<ConfirmationPopup> {
|
class _ConfirmationPopupState extends State<ConfirmationPopup> {
|
||||||
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
||||||
num price = 0;
|
double price = 0;
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
|
|
@ -67,7 +71,7 @@ class _ConfirmationPopupState extends State<ConfirmationPopup> {
|
||||||
text: "Prix à neuf : ",
|
text: "Prix à neuf : ",
|
||||||
style: TextStyle(fontWeight: FontWeight.bold),
|
style: TextStyle(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
TextSpan(text: widget.book.priceNew),
|
TextSpan(text: widget.book.priceNew.replaceAll("EUR", "€")),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -89,7 +93,7 @@ class _ConfirmationPopupState extends State<ConfirmationPopup> {
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
onSaved: (newValue) {
|
onSaved: (newValue) {
|
||||||
price = num.parse(newValue!);
|
price = double.parse(newValue!);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
: SizedBox(),
|
: SizedBox(),
|
||||||
|
|
@ -111,32 +115,57 @@ class _ConfirmationPopupState extends State<ConfirmationPopup> {
|
||||||
child: Text("Annuler"),
|
child: Text("Annuler"),
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () async {
|
||||||
switch (widget.viewModel.askPrice) {
|
var result = await widget.viewModel.sendBook(
|
||||||
case true:
|
widget.book,
|
||||||
if (_formKey.currentState!.validate()) {
|
widget.viewModel.currentOwner!,
|
||||||
_formKey.currentState!.save();
|
Bal(id: 1),
|
||||||
|
price,
|
||||||
|
);
|
||||||
|
switch (result) {
|
||||||
|
case Ok():
|
||||||
|
switch (widget.viewModel.askPrice) {
|
||||||
|
case true:
|
||||||
|
if (_formKey.currentState!.validate()) {
|
||||||
|
_formKey.currentState!.save();
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
"\"${widget.book.title}\" ($price€) a bien été enregistré",
|
||||||
|
),
|
||||||
|
behavior: SnackBarBehavior.floating,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
widget.exitPopup(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case false:
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
"\"${widget.book.title}\" (PL) a bien été enregistré",
|
||||||
|
),
|
||||||
|
behavior: SnackBarBehavior.floating,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
widget.exitPopup(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Error():
|
||||||
|
if (context.mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text(
|
content: Text(
|
||||||
"\"${widget.book.title}\" ($price) a bien été enregistré",
|
"Une erreur est survenue : ${result.error}",
|
||||||
),
|
),
|
||||||
behavior: SnackBarBehavior.floating,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
widget.exitPopup(context);
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case false:
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text(
|
|
||||||
"\"${widget.book.title}\" (PL) a bien été enregistré",
|
|
||||||
),
|
|
||||||
behavior: SnackBarBehavior.floating,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
widget.exitPopup(context);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Text("Valider"),
|
child: Text("Valider"),
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ class SellViewModel extends ChangeNotifier {
|
||||||
id: _scannedBooks.length,
|
id: _scannedBooks.length,
|
||||||
ownerId: 5,
|
ownerId: 5,
|
||||||
price: 5,
|
price: 5,
|
||||||
status: true,
|
available: true,
|
||||||
);
|
);
|
||||||
_scannedBooks.add(addedBook);
|
_scannedBooks.add(addedBook);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
|
||||||
27
lib/utils/overlay_boundary.dart
Normal file
27
lib/utils/overlay_boundary.dart
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class OverlayBoundary extends StatefulWidget {
|
||||||
|
const OverlayBoundary({super.key, required this.child});
|
||||||
|
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<OverlayBoundary> createState() => _OverlayBoundaryState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _OverlayBoundaryState extends State<OverlayBoundary> {
|
||||||
|
late final OverlayEntry _overlayEntry = OverlayEntry(
|
||||||
|
builder: (context) => widget.child,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didUpdateWidget(covariant OverlayBoundary oldWidget) {
|
||||||
|
super.didUpdateWidget(oldWidget);
|
||||||
|
_overlayEntry.markNeedsBuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Overlay(initialEntries: [_overlayEntry]);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in a new issue