From 44289e29dc45acd6be6c28032aa5637082d5bb51 Mon Sep 17 00:00:00 2001 From: mandreshope Date: Thu, 3 Jul 2025 17:20:44 +0300 Subject: [PATCH] feat: Adds product image field to data models MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Includes an `image` field in the `ProductStruct` and `ProductEntity` data models. Updates the ObjectBox schema and regenerates the necessary code to persist the new field. Refactors the `ProductScannedComponent` to accept a `ProductStruct` object, simplifying parameter passing. Updates the `ScannerPage` to build and pass the `ProductStruct` to the component, enabling the display of the product image and using the structured data for other details like quantity. The 'Marque' display is replaced with 'Quantité' in the component. --- .../entities/product/product_entity.dart | 4 +++ lib/backend/objectbox/objectbox-model.json | 7 ++++- lib/backend/objectbox/objectbox.g.dart | 23 ++++++++++++++-- .../schema/product/product_struct.dart | 1 + .../product/product_struct.freezed.dart | 27 ++++++++++--------- .../schema/product/product_struct.g.dart | 2 ++ lib/components/product_scanned_component.dart | 23 ++++++++-------- lib/pages/login_page/login_page_model.dart | 2 +- lib/pages/scanner_page/scanner_page.dart | 27 ++++++++++++------- 9 files changed, 79 insertions(+), 37 deletions(-) diff --git a/lib/backend/objectbox/entities/product/product_entity.dart b/lib/backend/objectbox/entities/product/product_entity.dart index a30c87f..c13a29e 100644 --- a/lib/backend/objectbox/entities/product/product_entity.dart +++ b/lib/backend/objectbox/entities/product/product_entity.dart @@ -12,6 +12,7 @@ class ProductEntity { String? description; String? price; String? quantity; + String? image; ProductEntity({ this.id = 0, @@ -20,6 +21,7 @@ class ProductEntity { this.description, this.price, this.quantity, + this.image, }); /// Convertir vers ProductStruct @@ -31,6 +33,7 @@ class ProductEntity { description: description, price: price, quantity: quantity, + image: image, ); } @@ -43,6 +46,7 @@ class ProductEntity { description: struct.description, price: struct.price, quantity: struct.quantity, + image: struct.image, ); } } diff --git a/lib/backend/objectbox/objectbox-model.json b/lib/backend/objectbox/objectbox-model.json index f7e44cf..0cdd6b2 100644 --- a/lib/backend/objectbox/objectbox-model.json +++ b/lib/backend/objectbox/objectbox-model.json @@ -5,7 +5,7 @@ "entities": [ { "id": "1:6757833172062715556", - "lastPropertyId": "6:7033704955625644592", + "lastPropertyId": "7:1825580906382154543", "name": "ProductEntity", "properties": [ { @@ -38,6 +38,11 @@ "id": "6:7033704955625644592", "name": "quantity", "type": 9 + }, + { + "id": "7:1825580906382154543", + "name": "image", + "type": 9 } ], "relations": [] diff --git a/lib/backend/objectbox/objectbox.g.dart b/lib/backend/objectbox/objectbox.g.dart index 3f382da..be94e25 100644 --- a/lib/backend/objectbox/objectbox.g.dart +++ b/lib/backend/objectbox/objectbox.g.dart @@ -22,7 +22,7 @@ final _entities = [ obx_int.ModelEntity( id: const obx_int.IdUid(1, 6757833172062715556), name: 'ProductEntity', - lastPropertyId: const obx_int.IdUid(6, 7033704955625644592), + lastPropertyId: const obx_int.IdUid(7, 1825580906382154543), flags: 0, properties: [ obx_int.ModelProperty( @@ -61,6 +61,12 @@ final _entities = [ type: 9, flags: 0, ), + obx_int.ModelProperty( + id: const obx_int.IdUid(7, 1825580906382154543), + name: 'image', + type: 9, + flags: 0, + ), ], relations: [], backlinks: [], @@ -143,13 +149,17 @@ obx_int.ModelDefinition getObjectBoxModel() { final quantityOffset = object.quantity == null ? null : fbb.writeString(object.quantity!); - fbb.startTable(7); + final imageOffset = object.image == null + ? null + : fbb.writeString(object.image!); + fbb.startTable(8); fbb.addInt64(0, object.id); fbb.addOffset(1, codeOffset); fbb.addOffset(2, nameOffset); fbb.addOffset(3, descriptionOffset); fbb.addOffset(4, priceOffset); fbb.addOffset(5, quantityOffset); + fbb.addOffset(6, imageOffset); fbb.finish(fbb.endTable()); return object.id; }, @@ -177,6 +187,9 @@ obx_int.ModelDefinition getObjectBoxModel() { final quantityParam = const fb.StringReader( asciiOptimization: true, ).vTableGetNullable(buffer, rootOffset, 14); + final imageParam = const fb.StringReader( + asciiOptimization: true, + ).vTableGetNullable(buffer, rootOffset, 16); final object = ProductEntity( id: idParam, code: codeParam, @@ -184,6 +197,7 @@ obx_int.ModelDefinition getObjectBoxModel() { description: descriptionParam, price: priceParam, quantity: quantityParam, + image: imageParam, ); return object; @@ -225,4 +239,9 @@ class ProductEntity_ { static final quantity = obx.QueryStringProperty( _entities[0].properties[5], ); + + /// See [ProductEntity.image]. + static final image = obx.QueryStringProperty( + _entities[0].properties[6], + ); } diff --git a/lib/backend/schema/product/product_struct.dart b/lib/backend/schema/product/product_struct.dart index 9a3e70b..1796ef4 100644 --- a/lib/backend/schema/product/product_struct.dart +++ b/lib/backend/schema/product/product_struct.dart @@ -12,6 +12,7 @@ abstract class ProductStruct with _$ProductStruct { String? description, String? price, String? quantity, + String? image, }) = _ProductStruct; factory ProductStruct.fromJson(Map json) => diff --git a/lib/backend/schema/product/product_struct.freezed.dart b/lib/backend/schema/product/product_struct.freezed.dart index b6efd58..317d4f7 100644 --- a/lib/backend/schema/product/product_struct.freezed.dart +++ b/lib/backend/schema/product/product_struct.freezed.dart @@ -16,7 +16,7 @@ T _$identity(T value) => value; /// @nodoc mixin _$ProductStruct { - int get id; String? get code; String? get name; String? get description; String? get price; String? get quantity; + int get id; String? get code; String? get name; String? get description; String? get price; String? get quantity; String? get image; /// Create a copy of ProductStruct /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -29,16 +29,16 @@ $ProductStructCopyWith get copyWith => _$ProductStructCopyWithImp @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is ProductStruct&&(identical(other.id, id) || other.id == id)&&(identical(other.code, code) || other.code == code)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&(identical(other.price, price) || other.price == price)&&(identical(other.quantity, quantity) || other.quantity == quantity)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is ProductStruct&&(identical(other.id, id) || other.id == id)&&(identical(other.code, code) || other.code == code)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&(identical(other.price, price) || other.price == price)&&(identical(other.quantity, quantity) || other.quantity == quantity)&&(identical(other.image, image) || other.image == image)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,id,code,name,description,price,quantity); +int get hashCode => Object.hash(runtimeType,id,code,name,description,price,quantity,image); @override String toString() { - return 'ProductStruct(id: $id, code: $code, name: $name, description: $description, price: $price, quantity: $quantity)'; + return 'ProductStruct(id: $id, code: $code, name: $name, description: $description, price: $price, quantity: $quantity, image: $image)'; } @@ -49,7 +49,7 @@ abstract mixin class $ProductStructCopyWith<$Res> { factory $ProductStructCopyWith(ProductStruct value, $Res Function(ProductStruct) _then) = _$ProductStructCopyWithImpl; @useResult $Res call({ - int id, String? code, String? name, String? description, String? price, String? quantity + int id, String? code, String? name, String? description, String? price, String? quantity, String? image }); @@ -66,7 +66,7 @@ class _$ProductStructCopyWithImpl<$Res> /// Create a copy of ProductStruct /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? code = freezed,Object? name = freezed,Object? description = freezed,Object? price = freezed,Object? quantity = freezed,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? id = null,Object? code = freezed,Object? name = freezed,Object? description = freezed,Object? price = freezed,Object? quantity = freezed,Object? image = freezed,}) { return _then(_self.copyWith( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as int,code: freezed == code ? _self.code : code // ignore: cast_nullable_to_non_nullable @@ -74,6 +74,7 @@ as String?,name: freezed == name ? _self.name : name // ignore: cast_nullable_to as String?,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable as String?,price: freezed == price ? _self.price : price // ignore: cast_nullable_to_non_nullable as String?,quantity: freezed == quantity ? _self.quantity : quantity // ignore: cast_nullable_to_non_nullable +as String?,image: freezed == image ? _self.image : image // ignore: cast_nullable_to_non_nullable as String?, )); } @@ -85,7 +86,7 @@ as String?, @JsonSerializable() class _ProductStruct implements ProductStruct { - _ProductStruct({this.id = 0, this.code, this.name, this.description, this.price, this.quantity}); + _ProductStruct({this.id = 0, this.code, this.name, this.description, this.price, this.quantity, this.image}); factory _ProductStruct.fromJson(Map json) => _$ProductStructFromJson(json); @override@JsonKey() final int id; @@ -94,6 +95,7 @@ class _ProductStruct implements ProductStruct { @override final String? description; @override final String? price; @override final String? quantity; +@override final String? image; /// Create a copy of ProductStruct /// with the given fields replaced by the non-null parameter values. @@ -108,16 +110,16 @@ Map toJson() { @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _ProductStruct&&(identical(other.id, id) || other.id == id)&&(identical(other.code, code) || other.code == code)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&(identical(other.price, price) || other.price == price)&&(identical(other.quantity, quantity) || other.quantity == quantity)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _ProductStruct&&(identical(other.id, id) || other.id == id)&&(identical(other.code, code) || other.code == code)&&(identical(other.name, name) || other.name == name)&&(identical(other.description, description) || other.description == description)&&(identical(other.price, price) || other.price == price)&&(identical(other.quantity, quantity) || other.quantity == quantity)&&(identical(other.image, image) || other.image == image)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,id,code,name,description,price,quantity); +int get hashCode => Object.hash(runtimeType,id,code,name,description,price,quantity,image); @override String toString() { - return 'ProductStruct(id: $id, code: $code, name: $name, description: $description, price: $price, quantity: $quantity)'; + return 'ProductStruct(id: $id, code: $code, name: $name, description: $description, price: $price, quantity: $quantity, image: $image)'; } @@ -128,7 +130,7 @@ abstract mixin class _$ProductStructCopyWith<$Res> implements $ProductStructCopy factory _$ProductStructCopyWith(_ProductStruct value, $Res Function(_ProductStruct) _then) = __$ProductStructCopyWithImpl; @override @useResult $Res call({ - int id, String? code, String? name, String? description, String? price, String? quantity + int id, String? code, String? name, String? description, String? price, String? quantity, String? image }); @@ -145,7 +147,7 @@ class __$ProductStructCopyWithImpl<$Res> /// Create a copy of ProductStruct /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? code = freezed,Object? name = freezed,Object? description = freezed,Object? price = freezed,Object? quantity = freezed,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? id = null,Object? code = freezed,Object? name = freezed,Object? description = freezed,Object? price = freezed,Object? quantity = freezed,Object? image = freezed,}) { return _then(_ProductStruct( id: null == id ? _self.id : id // ignore: cast_nullable_to_non_nullable as int,code: freezed == code ? _self.code : code // ignore: cast_nullable_to_non_nullable @@ -153,6 +155,7 @@ as String?,name: freezed == name ? _self.name : name // ignore: cast_nullable_to as String?,description: freezed == description ? _self.description : description // ignore: cast_nullable_to_non_nullable as String?,price: freezed == price ? _self.price : price // ignore: cast_nullable_to_non_nullable as String?,quantity: freezed == quantity ? _self.quantity : quantity // ignore: cast_nullable_to_non_nullable +as String?,image: freezed == image ? _self.image : image // ignore: cast_nullable_to_non_nullable as String?, )); } diff --git a/lib/backend/schema/product/product_struct.g.dart b/lib/backend/schema/product/product_struct.g.dart index da74061..5e5403a 100644 --- a/lib/backend/schema/product/product_struct.g.dart +++ b/lib/backend/schema/product/product_struct.g.dart @@ -14,6 +14,7 @@ _ProductStruct _$ProductStructFromJson(Map json) => description: json['description'] as String?, price: json['price'] as String?, quantity: json['quantity'] as String?, + image: json['image'] as String?, ); Map _$ProductStructToJson(_ProductStruct instance) => @@ -24,4 +25,5 @@ Map _$ProductStructToJson(_ProductStruct instance) => 'description': instance.description, 'price': instance.price, 'quantity': instance.quantity, + 'image': instance.image, }; diff --git a/lib/components/product_scanned_component.dart b/lib/components/product_scanned_component.dart index 4ab7a80..1a9aa71 100644 --- a/lib/components/product_scanned_component.dart +++ b/lib/components/product_scanned_component.dart @@ -1,20 +1,16 @@ +import 'package:barcode_scanner/backend/schema/product/product_struct.dart'; import 'package:barcode_scanner/themes/app_theme.dart'; import 'package:flutter/material.dart'; class ProductScannedComponent extends StatefulWidget { const ProductScannedComponent({ super.key, - required this.codeScanned, - required this.productName, - required this.brands, - required this.img, + required this.productStruct, this.onRescan, this.onDetails, }); - final String codeScanned; - final String productName; - final String brands; - final String img; + final ProductStruct productStruct; + final Future Function()? onRescan; final Function()? onDetails; @@ -76,7 +72,7 @@ class _ProductScannedComponentState extends State { Align( alignment: Alignment.topCenter, child: Image.network( - widget.img, + widget.productStruct.image ?? '', height: MediaQuery.sizeOf(context).height * .2, ), ), @@ -91,7 +87,7 @@ class _ProductScannedComponentState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('Code scanné:'), - Text(widget.codeScanned), + Text(widget.productStruct.id.toString()), ], ), Divider( @@ -106,7 +102,7 @@ class _ProductScannedComponentState extends State { Text('Produit: '), Expanded( child: Text( - widget.productName, + widget.productStruct.name ?? '', textAlign: TextAlign.end, ), ), @@ -120,7 +116,10 @@ class _ProductScannedComponentState extends State { Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [Text('Marque:'), Text(widget.brands)], + children: [ + Text('Quantité:'), + Text(widget.productStruct.quantity ?? ''), + ], ), Divider( height: 1.0, diff --git a/lib/pages/login_page/login_page_model.dart b/lib/pages/login_page/login_page_model.dart index 6ee305d..ae501f3 100644 --- a/lib/pages/login_page/login_page_model.dart +++ b/lib/pages/login_page/login_page_model.dart @@ -95,7 +95,7 @@ class LoginPageModel extends StateNotifier { user.setToLocalStorage(), ]); state = state.copyWith(loading: false, status: LoginPageStateStatus.logged); - debugPrint("$token"); + debugPrint(token); } Future logOut() async { diff --git a/lib/pages/scanner_page/scanner_page.dart b/lib/pages/scanner_page/scanner_page.dart index 94c0ab1..287c69b 100644 --- a/lib/pages/scanner_page/scanner_page.dart +++ b/lib/pages/scanner_page/scanner_page.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:barcode_scanner/backend/api/api_calls.dart'; +import 'package:barcode_scanner/backend/schema/product/product_struct.dart'; import 'package:barcode_scanner/components/product_scanned_component.dart'; import 'package:barcode_scanner/router/go_secure_router_builder.dart'; import 'package:barcode_scanner/themes/app_theme.dart'; @@ -104,6 +105,13 @@ class _ScannerPageState extends ConsumerState debugPrint('Nom du produit : ${product["product_name"]}'); debugPrint('Marque : ${product["brands"]}'); debugPrint('Image : ${product["image_url"]}'); + final productStruct = ProductStruct( + id: int.parse(product["id"]), + name: product["product_name"], + image: product["image_thumb_url"], + description: product["categories"], + quantity: product["quantity"], + ); //show dialog await showDialog( barrierDismissible: false, @@ -125,10 +133,7 @@ class _ScannerPageState extends ConsumerState child: SizedBox( width: MediaQuery.sizeOf(context).width * 0.9, child: ProductScannedComponent( - img: product["image_url"], - productName: product["product_name"], - brands: product["brands"], - codeScanned: qrcodeValue, + productStruct: productStruct, onRescan: () async { Navigator.of(context).pop(); qrcodeFound = false; @@ -171,6 +176,13 @@ class _ScannerPageState extends ConsumerState debugPrint('Nom du produit : ${product["product_name"]}'); debugPrint('Marque : ${product["brands"]}'); debugPrint('Image : ${product["image_url"]}'); + final productStruct = ProductStruct( + id: int.parse(product["id"]), + image: product["image_thumb_url"], + name: product["product_name"], + description: product["categories"], + quantity: product["quantity"], + ); //show dialog await showDialog( barrierDismissible: false, @@ -192,10 +204,7 @@ class _ScannerPageState extends ConsumerState child: SizedBox( width: MediaQuery.sizeOf(context).width * 0.9, child: ProductScannedComponent( - img: product["image_url"], - productName: product["product_name"], - brands: product["brands"], - codeScanned: qrcodeValue, + productStruct: productStruct, onRescan: () async { Navigator.of(context).pop(); qrcodeFound = false; @@ -245,7 +254,7 @@ class _ScannerPageState extends ConsumerState child: IconButton( icon: Icon(Icons.help_outline, color: Colors.white, size: 24.0), onPressed: () { - print('IconButton pressed ...'); + debugPrint('IconButton pressed ...'); }, ), ),