feat: Integrates ObjectBox and updates Product ID

Adds the ObjectBox database dependency for local data persistence.

Updates the Product ID field type from nullable String to non-nullable int with a default value of 0 to align with ObjectBox's integer ID requirements. Includes necessary generated files for plugin registration and model serialization.
This commit is contained in:
mandreshope 2025-07-03 16:01:45 +03:00
parent 28a8027e20
commit 83a20c548b
13 changed files with 408 additions and 13 deletions

View File

@ -0,0 +1,48 @@
import 'package:barcode_scanner/backend/schema/product/product_struct.dart';
import 'package:objectbox/objectbox.dart';
/// Modèle de base de données ObjectBox
@Entity()
class ProductEntity {
@Id()
int id;
String? code;
String? name;
String? description;
String? price;
String? quantity;
ProductEntity({
this.id = 0,
this.code,
this.name,
this.description,
this.price,
this.quantity,
});
/// Convertir vers ProductStruct
ProductStruct toStruct() {
return ProductStruct(
id: id,
code: code,
name: name,
description: description,
price: price,
quantity: quantity,
);
}
/// Créer une instance de ProductEntity à partir de ProductStruct
static ProductEntity fromStruct(ProductStruct struct) {
return ProductEntity(
id: struct.id,
code: struct.code,
name: struct.name,
description: struct.description,
price: struct.price,
quantity: struct.quantity,
);
}
}

View File

@ -0,0 +1,57 @@
{
"_note1": "KEEP THIS FILE! Check it into a version control system (VCS) like git.",
"_note2": "ObjectBox manages crucial IDs for your object model. See docs for details.",
"_note3": "If you have VCS merge conflicts, you must resolve them according to ObjectBox docs.",
"entities": [
{
"id": "1:6757833172062715556",
"lastPropertyId": "6:7033704955625644592",
"name": "ProductEntity",
"properties": [
{
"id": "1:1853465479129290672",
"name": "id",
"type": 6,
"flags": 1
},
{
"id": "2:4521897043130066476",
"name": "code",
"type": 9
},
{
"id": "3:2561289170534233438",
"name": "name",
"type": 9
},
{
"id": "4:6084891210993334692",
"name": "description",
"type": 9
},
{
"id": "5:883454706727408240",
"name": "price",
"type": 9
},
{
"id": "6:7033704955625644592",
"name": "quantity",
"type": 9
}
],
"relations": []
}
],
"lastEntityId": "1:6757833172062715556",
"lastIndexId": "0:0",
"lastRelationId": "0:0",
"lastSequenceId": "0:0",
"modelVersion": 5,
"modelVersionParserMinimum": 5,
"retiredEntityUids": [],
"retiredIndexUids": [],
"retiredPropertyUids": [],
"retiredRelationUids": [],
"version": 1
}

View File

@ -0,0 +1,228 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// This code was generated by ObjectBox. To update it run the generator again
// with `dart run build_runner build`.
// See also https://docs.objectbox.io/getting-started#generate-objectbox-code
// ignore_for_file: camel_case_types, depend_on_referenced_packages
// coverage:ignore-file
import 'dart:typed_data';
import 'package:flat_buffers/flat_buffers.dart' as fb;
import 'package:objectbox/internal.dart'
as obx_int; // generated code can access "internal" functionality
import 'package:objectbox/objectbox.dart' as obx;
import 'package:objectbox_flutter_libs/objectbox_flutter_libs.dart';
import '../../backend/objectbox/entities/product/product_entity.dart';
export 'package:objectbox/objectbox.dart'; // so that callers only have to import this file
final _entities = <obx_int.ModelEntity>[
obx_int.ModelEntity(
id: const obx_int.IdUid(1, 6757833172062715556),
name: 'ProductEntity',
lastPropertyId: const obx_int.IdUid(6, 7033704955625644592),
flags: 0,
properties: <obx_int.ModelProperty>[
obx_int.ModelProperty(
id: const obx_int.IdUid(1, 1853465479129290672),
name: 'id',
type: 6,
flags: 1,
),
obx_int.ModelProperty(
id: const obx_int.IdUid(2, 4521897043130066476),
name: 'code',
type: 9,
flags: 0,
),
obx_int.ModelProperty(
id: const obx_int.IdUid(3, 2561289170534233438),
name: 'name',
type: 9,
flags: 0,
),
obx_int.ModelProperty(
id: const obx_int.IdUid(4, 6084891210993334692),
name: 'description',
type: 9,
flags: 0,
),
obx_int.ModelProperty(
id: const obx_int.IdUid(5, 883454706727408240),
name: 'price',
type: 9,
flags: 0,
),
obx_int.ModelProperty(
id: const obx_int.IdUid(6, 7033704955625644592),
name: 'quantity',
type: 9,
flags: 0,
),
],
relations: <obx_int.ModelRelation>[],
backlinks: <obx_int.ModelBacklink>[],
),
];
/// Shortcut for [obx.Store.new] that passes [getObjectBoxModel] and for Flutter
/// apps by default a [directory] using `defaultStoreDirectory()` from the
/// ObjectBox Flutter library.
///
/// Note: for desktop apps it is recommended to specify a unique [directory].
///
/// See [obx.Store.new] for an explanation of all parameters.
///
/// For Flutter apps, also calls `loadObjectBoxLibraryAndroidCompat()` from
/// the ObjectBox Flutter library to fix loading the native ObjectBox library
/// on Android 6 and older.
Future<obx.Store> openStore({
String? directory,
int? maxDBSizeInKB,
int? maxDataSizeInKB,
int? fileMode,
int? maxReaders,
bool queriesCaseSensitiveDefault = true,
String? macosApplicationGroup,
}) async {
await loadObjectBoxLibraryAndroidCompat();
return obx.Store(
getObjectBoxModel(),
directory: directory ?? (await defaultStoreDirectory()).path,
maxDBSizeInKB: maxDBSizeInKB,
maxDataSizeInKB: maxDataSizeInKB,
fileMode: fileMode,
maxReaders: maxReaders,
queriesCaseSensitiveDefault: queriesCaseSensitiveDefault,
macosApplicationGroup: macosApplicationGroup,
);
}
/// Returns the ObjectBox model definition for this project for use with
/// [obx.Store.new].
obx_int.ModelDefinition getObjectBoxModel() {
final model = obx_int.ModelInfo(
entities: _entities,
lastEntityId: const obx_int.IdUid(1, 6757833172062715556),
lastIndexId: const obx_int.IdUid(0, 0),
lastRelationId: const obx_int.IdUid(0, 0),
lastSequenceId: const obx_int.IdUid(0, 0),
retiredEntityUids: const [],
retiredIndexUids: const [],
retiredPropertyUids: const [],
retiredRelationUids: const [],
modelVersion: 5,
modelVersionParserMinimum: 5,
version: 1,
);
final bindings = <Type, obx_int.EntityDefinition>{
ProductEntity: obx_int.EntityDefinition<ProductEntity>(
model: _entities[0],
toOneRelations: (ProductEntity object) => [],
toManyRelations: (ProductEntity object) => {},
getId: (ProductEntity object) => object.id,
setId: (ProductEntity object, int id) {
object.id = id;
},
objectToFB: (ProductEntity object, fb.Builder fbb) {
final codeOffset = object.code == null
? null
: fbb.writeString(object.code!);
final nameOffset = object.name == null
? null
: fbb.writeString(object.name!);
final descriptionOffset = object.description == null
? null
: fbb.writeString(object.description!);
final priceOffset = object.price == null
? null
: fbb.writeString(object.price!);
final quantityOffset = object.quantity == null
? null
: fbb.writeString(object.quantity!);
fbb.startTable(7);
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.finish(fbb.endTable());
return object.id;
},
objectFromFB: (obx.Store store, ByteData fbData) {
final buffer = fb.BufferContext(fbData);
final rootOffset = buffer.derefObject(0);
final idParam = const fb.Int64Reader().vTableGet(
buffer,
rootOffset,
4,
0,
);
final codeParam = const fb.StringReader(
asciiOptimization: true,
).vTableGetNullable(buffer, rootOffset, 6);
final nameParam = const fb.StringReader(
asciiOptimization: true,
).vTableGetNullable(buffer, rootOffset, 8);
final descriptionParam = const fb.StringReader(
asciiOptimization: true,
).vTableGetNullable(buffer, rootOffset, 10);
final priceParam = const fb.StringReader(
asciiOptimization: true,
).vTableGetNullable(buffer, rootOffset, 12);
final quantityParam = const fb.StringReader(
asciiOptimization: true,
).vTableGetNullable(buffer, rootOffset, 14);
final object = ProductEntity(
id: idParam,
code: codeParam,
name: nameParam,
description: descriptionParam,
price: priceParam,
quantity: quantityParam,
);
return object;
},
),
};
return obx_int.ModelDefinition(model, bindings);
}
/// [ProductEntity] entity fields to define ObjectBox queries.
class ProductEntity_ {
/// See [ProductEntity.id].
static final id = obx.QueryIntegerProperty<ProductEntity>(
_entities[0].properties[0],
);
/// See [ProductEntity.code].
static final code = obx.QueryStringProperty<ProductEntity>(
_entities[0].properties[1],
);
/// See [ProductEntity.name].
static final name = obx.QueryStringProperty<ProductEntity>(
_entities[0].properties[2],
);
/// See [ProductEntity.description].
static final description = obx.QueryStringProperty<ProductEntity>(
_entities[0].properties[3],
);
/// See [ProductEntity.price].
static final price = obx.QueryStringProperty<ProductEntity>(
_entities[0].properties[4],
);
/// See [ProductEntity.quantity].
static final quantity = obx.QueryStringProperty<ProductEntity>(
_entities[0].properties[5],
);
}

View File

@ -6,7 +6,7 @@ part 'product_struct.g.dart';
@Freezed(toJson: true)
abstract class ProductStruct with _$ProductStruct {
factory ProductStruct({
String? id,
@Default(0) int id,
String? code,
String? name,
String? description,

View File

@ -16,7 +16,7 @@ T _$identity<T>(T value) => value;
/// @nodoc
mixin _$ProductStruct {
String? 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;
/// Create a copy of ProductStruct
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@ -49,7 +49,7 @@ abstract mixin class $ProductStructCopyWith<$Res> {
factory $ProductStructCopyWith(ProductStruct value, $Res Function(ProductStruct) _then) = _$ProductStructCopyWithImpl;
@useResult
$Res call({
String? id, String? code, String? name, String? description, String? price, String? quantity
int id, String? code, String? name, String? description, String? price, String? quantity
});
@ -66,10 +66,10 @@ 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 = freezed,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,}) {
return _then(_self.copyWith(
id: freezed == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String?,code: freezed == code ? _self.code : code // ignore: cast_nullable_to_non_nullable
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
as String?,name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
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
@ -85,10 +85,10 @@ as String?,
@JsonSerializable()
class _ProductStruct implements ProductStruct {
_ProductStruct({this.id, this.code, this.name, this.description, this.price, this.quantity});
_ProductStruct({this.id = 0, this.code, this.name, this.description, this.price, this.quantity});
factory _ProductStruct.fromJson(Map<String, dynamic> json) => _$ProductStructFromJson(json);
@override final String? id;
@override@JsonKey() final int id;
@override final String? code;
@override final String? name;
@override final String? description;
@ -128,7 +128,7 @@ abstract mixin class _$ProductStructCopyWith<$Res> implements $ProductStructCopy
factory _$ProductStructCopyWith(_ProductStruct value, $Res Function(_ProductStruct) _then) = __$ProductStructCopyWithImpl;
@override @useResult
$Res call({
String? id, String? code, String? name, String? description, String? price, String? quantity
int id, String? code, String? name, String? description, String? price, String? quantity
});
@ -145,10 +145,10 @@ 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 = freezed,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,}) {
return _then(_ProductStruct(
id: freezed == id ? _self.id : id // ignore: cast_nullable_to_non_nullable
as String?,code: freezed == code ? _self.code : code // ignore: cast_nullable_to_non_nullable
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
as String?,name: freezed == name ? _self.name : name // ignore: cast_nullable_to_non_nullable
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

View File

@ -8,7 +8,7 @@ part of 'product_struct.dart';
_ProductStruct _$ProductStructFromJson(Map<String, dynamic> json) =>
_ProductStruct(
id: json['id'] as String?,
id: (json['id'] as num?)?.toInt() ?? 0,
code: json['code'] as String?,
name: json['name'] as String?,
description: json['description'] as String?,

View File

@ -7,9 +7,13 @@
#include "generated_plugin_registrant.h"
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
#include <objectbox_flutter_libs/objectbox_flutter_libs_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
g_autoptr(FlPluginRegistrar) objectbox_flutter_libs_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "ObjectboxFlutterLibsPlugin");
objectbox_flutter_libs_plugin_register_with_registrar(objectbox_flutter_libs_registrar);
}

View File

@ -4,6 +4,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
flutter_secure_storage_linux
objectbox_flutter_libs
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST

View File

@ -8,6 +8,7 @@ import Foundation
import connectivity_plus
import flutter_secure_storage_macos
import mobile_scanner
import objectbox_flutter_libs
import path_provider_foundation
import shared_preferences_foundation
@ -15,6 +16,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin"))
ObjectboxFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "ObjectboxFlutterLibsPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
}

View File

@ -265,6 +265,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.1.1"
flat_buffers:
dependency: transitive
description:
name: flat_buffers
sha256: "380bdcba5664a718bfd4ea20a45d39e13684f5318fcd8883066a55e21f37f4c3"
url: "https://pub.dev"
source: hosted
version: "23.5.26"
flutter:
dependency: "direct main"
description: flutter
@ -581,6 +589,30 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.5.0"
objectbox:
dependency: "direct main"
description:
name: objectbox
sha256: "25c2e24b417d938decb5598682dc831bc6a21856eaae65affbc57cfad326808d"
url: "https://pub.dev"
source: hosted
version: "4.3.0"
objectbox_flutter_libs:
dependency: "direct main"
description:
name: objectbox_flutter_libs
sha256: "574b0233ba79a7159fca9049c67974f790a2180b6141d4951112b20bd146016a"
url: "https://pub.dev"
source: hosted
version: "4.3.0"
objectbox_generator:
dependency: "direct dev"
description:
name: objectbox_generator
sha256: "1b17e9168d03706b5bb895b5f36f4301aa7c973ac30ff761b205b1ca3e2e3865"
url: "https://pub.dev"
source: hosted
version: "4.3.0"
package_config:
dependency: transitive
description:
@ -669,6 +701,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.8"
pointycastle:
dependency: transitive
description:
name: pointycastle
sha256: "92aa3841d083cc4b0f4709b5c74fd6409a3e6ba833ffc7dc6a8fee096366acf5"
url: "https://pub.dev"
source: hosted
version: "4.0.0"
pool:
dependency: transitive
description:

View File

@ -50,12 +50,15 @@ dependencies:
flutter_secure_storage: ^9.2.4
google_fonts: ^6.2.1
shared_preferences: ^2.5.3
objectbox: ^4.3.0
objectbox_flutter_libs: any
dev_dependencies:
flutter_test:
sdk: flutter
go_router_builder: ^3.0.1
build_runner: ^2.4.15
objectbox_generator: any
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
@ -76,6 +79,14 @@ flutter_icons:
remove_alpha_ios: true
min_sdk_android: 21
objectbox:
# Writes objectbox-model.json and objectbox.g.dart to lib/objectbox (and test/objectbox).
output_dir: backend/objectbox
# Or optionally specify the lib and test output folder separately.
# output_dir:
# lib: custom
# test: other
# The following section is specific to Flutter packages.
flutter:
# The following line ensures that the Material Icons font is

View File

@ -8,10 +8,13 @@
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
#include <objectbox_flutter_libs/objectbox_flutter_libs_plugin.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
ConnectivityPlusWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
ObjectboxFlutterLibsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("ObjectboxFlutterLibsPlugin"));
}

View File

@ -5,6 +5,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
connectivity_plus
flutter_secure_storage_windows
objectbox_flutter_libs
)
list(APPEND FLUTTER_FFI_PLUGIN_LIST