runable
This commit is contained in:
101
lib/core/database/database_initializer.dart
Normal file
101
lib/core/database/database_initializer.dart
Normal file
@@ -0,0 +1,101 @@
|
||||
import 'package:retail/core/database/hive_database.dart';
|
||||
import 'package:retail/core/database/seed_data.dart';
|
||||
|
||||
/// Database initialization and seeding utility
|
||||
class DatabaseInitializer {
|
||||
final HiveDatabase _database;
|
||||
|
||||
DatabaseInitializer(this._database);
|
||||
|
||||
/// Initialize database and seed with sample data if empty
|
||||
Future<void> initialize({bool seedIfEmpty = true}) async {
|
||||
// Initialize Hive
|
||||
await _database.init();
|
||||
|
||||
// Seed data if boxes are empty and seeding is enabled
|
||||
if (seedIfEmpty) {
|
||||
await _seedIfEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
/// Seed database with sample data if empty
|
||||
Future<void> _seedIfEmpty() async {
|
||||
final productsBox = _database.productsBox;
|
||||
final categoriesBox = _database.categoriesBox;
|
||||
|
||||
// Check if database is empty
|
||||
if (productsBox.isEmpty && categoriesBox.isEmpty) {
|
||||
await seedDatabase(forceReseed: false);
|
||||
}
|
||||
}
|
||||
|
||||
/// Seed database with sample data
|
||||
Future<void> seedDatabase({bool forceReseed = false}) async {
|
||||
final productsBox = _database.productsBox;
|
||||
final categoriesBox = _database.categoriesBox;
|
||||
|
||||
// Clear existing data if force reseed
|
||||
if (forceReseed) {
|
||||
await productsBox.clear();
|
||||
await categoriesBox.clear();
|
||||
}
|
||||
|
||||
// Only seed if boxes are empty
|
||||
if (productsBox.isEmpty && categoriesBox.isEmpty) {
|
||||
// Generate and save categories
|
||||
final categories = SeedData.generateCategories();
|
||||
final categoriesMap = {
|
||||
for (var category in categories) category.id: category
|
||||
};
|
||||
await categoriesBox.putAll(categoriesMap);
|
||||
|
||||
// Generate and save products
|
||||
final products = SeedData.generateProducts();
|
||||
final productsMap = {
|
||||
for (var product in products) product.id: product
|
||||
};
|
||||
await productsBox.putAll(productsMap);
|
||||
|
||||
// Update category product counts
|
||||
await _updateCategoryProductCounts();
|
||||
}
|
||||
}
|
||||
|
||||
/// Update product counts for all categories
|
||||
Future<void> _updateCategoryProductCounts() async {
|
||||
final productsBox = _database.productsBox;
|
||||
final categoriesBox = _database.categoriesBox;
|
||||
|
||||
// Count products per category
|
||||
final productCounts = <String, int>{};
|
||||
for (var product in productsBox.values) {
|
||||
productCounts[product.categoryId] =
|
||||
(productCounts[product.categoryId] ?? 0) + 1;
|
||||
}
|
||||
|
||||
// Update category product counts
|
||||
for (var category in categoriesBox.values) {
|
||||
final count = productCounts[category.id] ?? 0;
|
||||
if (category.productCount != count) {
|
||||
final updated = category.copyWith(productCount: count);
|
||||
await categoriesBox.put(category.id, updated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Reset database (clear all data and reseed)
|
||||
Future<void> resetDatabase() async {
|
||||
await _database.clearAllData();
|
||||
await seedDatabase(forceReseed: true);
|
||||
}
|
||||
|
||||
/// Get database statistics
|
||||
Map<String, dynamic> getDatabaseStats() {
|
||||
return _database.getStatistics();
|
||||
}
|
||||
|
||||
/// Compact database (optimize storage)
|
||||
Future<void> compactDatabase() async {
|
||||
await _database.compactAll();
|
||||
}
|
||||
}
|
||||
171
lib/core/database/hive_database.dart
Normal file
171
lib/core/database/hive_database.dart
Normal file
@@ -0,0 +1,171 @@
|
||||
import 'package:hive_ce/hive.dart';
|
||||
import 'package:hive_ce_flutter/hive_flutter.dart';
|
||||
import 'package:retail/core/constants/storage_constants.dart';
|
||||
import 'package:retail/features/products/data/models/product_model.dart';
|
||||
import 'package:retail/features/categories/data/models/category_model.dart';
|
||||
import 'package:retail/features/home/data/models/cart_item_model.dart';
|
||||
import 'package:retail/features/home/data/models/transaction_model.dart';
|
||||
import 'package:retail/features/settings/data/models/app_settings_model.dart';
|
||||
|
||||
/// Hive database initialization and management
|
||||
class HiveDatabase {
|
||||
static HiveDatabase? _instance;
|
||||
static HiveDatabase get instance => _instance ??= HiveDatabase._();
|
||||
|
||||
HiveDatabase._();
|
||||
|
||||
bool _isInitialized = false;
|
||||
|
||||
/// Initialize Hive database
|
||||
Future<void> init() async {
|
||||
if (_isInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Initialize Hive for Flutter
|
||||
await Hive.initFlutter();
|
||||
|
||||
// Register all type adapters
|
||||
_registerAdapters();
|
||||
|
||||
// Open all boxes
|
||||
await _openBoxes();
|
||||
|
||||
// Initialize default settings if needed
|
||||
await _initializeDefaults();
|
||||
|
||||
_isInitialized = true;
|
||||
} catch (e) {
|
||||
throw Exception('Failed to initialize Hive database: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Register all Hive type adapters
|
||||
void _registerAdapters() {
|
||||
// Register only if not already registered
|
||||
if (!Hive.isAdapterRegistered(StorageConstants.productTypeId)) {
|
||||
Hive.registerAdapter(ProductModelAdapter());
|
||||
}
|
||||
if (!Hive.isAdapterRegistered(StorageConstants.categoryTypeId)) {
|
||||
Hive.registerAdapter(CategoryModelAdapter());
|
||||
}
|
||||
if (!Hive.isAdapterRegistered(StorageConstants.cartItemTypeId)) {
|
||||
Hive.registerAdapter(CartItemModelAdapter());
|
||||
}
|
||||
if (!Hive.isAdapterRegistered(StorageConstants.transactionTypeId)) {
|
||||
Hive.registerAdapter(TransactionModelAdapter());
|
||||
}
|
||||
if (!Hive.isAdapterRegistered(StorageConstants.appSettingsTypeId)) {
|
||||
Hive.registerAdapter(AppSettingsModelAdapter());
|
||||
}
|
||||
}
|
||||
|
||||
/// Open all required boxes
|
||||
Future<void> _openBoxes() async {
|
||||
await Future.wait([
|
||||
Hive.openBox<ProductModel>(StorageConstants.productsBox),
|
||||
Hive.openBox<CategoryModel>(StorageConstants.categoriesBox),
|
||||
Hive.openBox<CartItemModel>(StorageConstants.cartBox),
|
||||
Hive.openBox<TransactionModel>(StorageConstants.transactionsBox),
|
||||
Hive.openBox<AppSettingsModel>(StorageConstants.settingsBox),
|
||||
]);
|
||||
}
|
||||
|
||||
/// Initialize default settings and seed data if first launch
|
||||
Future<void> _initializeDefaults() async {
|
||||
final settingsBox = Hive.box<AppSettingsModel>(StorageConstants.settingsBox);
|
||||
|
||||
// Initialize default settings if not exists
|
||||
if (settingsBox.isEmpty) {
|
||||
await settingsBox.put(
|
||||
'app_settings',
|
||||
AppSettingsModel.defaultSettings(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a specific box by name
|
||||
Box<T> getBox<T>(String boxName) {
|
||||
return Hive.box<T>(boxName);
|
||||
}
|
||||
|
||||
/// Get products box
|
||||
Box<ProductModel> get productsBox =>
|
||||
Hive.box<ProductModel>(StorageConstants.productsBox);
|
||||
|
||||
/// Get categories box
|
||||
Box<CategoryModel> get categoriesBox =>
|
||||
Hive.box<CategoryModel>(StorageConstants.categoriesBox);
|
||||
|
||||
/// Get cart box
|
||||
Box<CartItemModel> get cartBox =>
|
||||
Hive.box<CartItemModel>(StorageConstants.cartBox);
|
||||
|
||||
/// Get transactions box
|
||||
Box<TransactionModel> get transactionsBox =>
|
||||
Hive.box<TransactionModel>(StorageConstants.transactionsBox);
|
||||
|
||||
/// Get settings box
|
||||
Box<AppSettingsModel> get settingsBox =>
|
||||
Hive.box<AppSettingsModel>(StorageConstants.settingsBox);
|
||||
|
||||
/// Clear all data from all boxes (useful for logout or reset)
|
||||
Future<void> clearAllData() async {
|
||||
await Future.wait([
|
||||
productsBox.clear(),
|
||||
categoriesBox.clear(),
|
||||
cartBox.clear(),
|
||||
transactionsBox.clear(),
|
||||
// Don't clear settings
|
||||
]);
|
||||
}
|
||||
|
||||
/// Clear cart only
|
||||
Future<void> clearCart() async {
|
||||
await cartBox.clear();
|
||||
}
|
||||
|
||||
/// Compact all boxes (optimize storage)
|
||||
Future<void> compactAll() async {
|
||||
await Future.wait([
|
||||
productsBox.compact(),
|
||||
categoriesBox.compact(),
|
||||
cartBox.compact(),
|
||||
transactionsBox.compact(),
|
||||
settingsBox.compact(),
|
||||
]);
|
||||
}
|
||||
|
||||
/// Close all boxes
|
||||
Future<void> closeAll() async {
|
||||
await Hive.close();
|
||||
_isInitialized = false;
|
||||
}
|
||||
|
||||
/// Delete all boxes (complete database reset)
|
||||
Future<void> deleteAll() async {
|
||||
await Future.wait([
|
||||
Hive.deleteBoxFromDisk(StorageConstants.productsBox),
|
||||
Hive.deleteBoxFromDisk(StorageConstants.categoriesBox),
|
||||
Hive.deleteBoxFromDisk(StorageConstants.cartBox),
|
||||
Hive.deleteBoxFromDisk(StorageConstants.transactionsBox),
|
||||
Hive.deleteBoxFromDisk(StorageConstants.settingsBox),
|
||||
]);
|
||||
_isInitialized = false;
|
||||
}
|
||||
|
||||
/// Get database statistics
|
||||
Map<String, dynamic> getStatistics() {
|
||||
return {
|
||||
'products': productsBox.length,
|
||||
'categories': categoriesBox.length,
|
||||
'cartItems': cartBox.length,
|
||||
'transactions': transactionsBox.length,
|
||||
'isInitialized': _isInitialized,
|
||||
};
|
||||
}
|
||||
|
||||
/// Check if database is initialized
|
||||
bool get isInitialized => _isInitialized;
|
||||
}
|
||||
210
lib/core/database/seed_data.dart
Normal file
210
lib/core/database/seed_data.dart
Normal file
@@ -0,0 +1,210 @@
|
||||
import 'package:uuid/uuid.dart';
|
||||
import 'package:retail/features/products/data/models/product_model.dart';
|
||||
import 'package:retail/features/categories/data/models/category_model.dart';
|
||||
|
||||
/// Seed data generator for testing and initial app setup
|
||||
class SeedData {
|
||||
static const _uuid = Uuid();
|
||||
|
||||
/// Generate sample categories
|
||||
static List<CategoryModel> generateCategories() {
|
||||
final now = DateTime.now();
|
||||
|
||||
return [
|
||||
CategoryModel(
|
||||
id: 'cat_electronics',
|
||||
name: 'Electronics',
|
||||
description: 'Electronic devices and accessories',
|
||||
iconPath: 'devices',
|
||||
color: '#2196F3', // Blue
|
||||
productCount: 0,
|
||||
createdAt: now.subtract(const Duration(days: 60)),
|
||||
),
|
||||
CategoryModel(
|
||||
id: 'cat_appliances',
|
||||
name: 'Home Appliances',
|
||||
description: 'Kitchen and home appliances',
|
||||
iconPath: 'kitchen',
|
||||
color: '#4CAF50', // Green
|
||||
productCount: 0,
|
||||
createdAt: now.subtract(const Duration(days: 55)),
|
||||
),
|
||||
CategoryModel(
|
||||
id: 'cat_sports',
|
||||
name: 'Sports & Fitness',
|
||||
description: 'Sports equipment and fitness gear',
|
||||
iconPath: 'fitness_center',
|
||||
color: '#FF9800', // Orange
|
||||
productCount: 0,
|
||||
createdAt: now.subtract(const Duration(days: 50)),
|
||||
),
|
||||
CategoryModel(
|
||||
id: 'cat_fashion',
|
||||
name: 'Fashion',
|
||||
description: 'Clothing, shoes, and accessories',
|
||||
iconPath: 'checkroom',
|
||||
color: '#E91E63', // Pink
|
||||
productCount: 0,
|
||||
createdAt: now.subtract(const Duration(days: 45)),
|
||||
),
|
||||
CategoryModel(
|
||||
id: 'cat_books',
|
||||
name: 'Books & Media',
|
||||
description: 'Books, magazines, and media',
|
||||
iconPath: 'book',
|
||||
color: '#9C27B0', // Purple
|
||||
productCount: 0,
|
||||
createdAt: now.subtract(const Duration(days: 40)),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
/// Generate sample products
|
||||
static List<ProductModel> generateProducts() {
|
||||
final now = DateTime.now();
|
||||
|
||||
return [
|
||||
// Electronics (3 products)
|
||||
ProductModel(
|
||||
id: 'prod_${_uuid.v4()}',
|
||||
name: 'Wireless Headphones',
|
||||
description: 'Premium noise-cancelling wireless headphones with 30-hour battery life',
|
||||
price: 299.99,
|
||||
imageUrl: 'https://picsum.photos/seed/headphones/400/400',
|
||||
categoryId: 'cat_electronics',
|
||||
stockQuantity: 25,
|
||||
isAvailable: true,
|
||||
createdAt: now.subtract(const Duration(days: 30)),
|
||||
updatedAt: now.subtract(const Duration(days: 1)),
|
||||
),
|
||||
ProductModel(
|
||||
id: 'prod_${_uuid.v4()}',
|
||||
name: 'Smart Watch',
|
||||
description: 'Fitness tracking smart watch with heart rate monitor and GPS',
|
||||
price: 199.99,
|
||||
imageUrl: 'https://picsum.photos/seed/smartwatch/400/400',
|
||||
categoryId: 'cat_electronics',
|
||||
stockQuantity: 15,
|
||||
isAvailable: true,
|
||||
createdAt: now.subtract(const Duration(days: 25)),
|
||||
updatedAt: now.subtract(const Duration(days: 2)),
|
||||
),
|
||||
ProductModel(
|
||||
id: 'prod_${_uuid.v4()}',
|
||||
name: 'Laptop Stand',
|
||||
description: 'Adjustable aluminum laptop stand with ergonomic design',
|
||||
price: 39.99,
|
||||
imageUrl: 'https://picsum.photos/seed/laptopstand/400/400',
|
||||
categoryId: 'cat_electronics',
|
||||
stockQuantity: 20,
|
||||
isAvailable: true,
|
||||
createdAt: now.subtract(const Duration(days: 20)),
|
||||
updatedAt: now.subtract(const Duration(days: 1)),
|
||||
),
|
||||
|
||||
// Home Appliances (2 products)
|
||||
ProductModel(
|
||||
id: 'prod_${_uuid.v4()}',
|
||||
name: 'Coffee Maker',
|
||||
description: 'Automatic drip coffee maker with programmable timer and thermal carafe',
|
||||
price: 79.99,
|
||||
imageUrl: 'https://picsum.photos/seed/coffeemaker/400/400',
|
||||
categoryId: 'cat_appliances',
|
||||
stockQuantity: 8,
|
||||
isAvailable: true,
|
||||
createdAt: now.subtract(const Duration(days: 18)),
|
||||
updatedAt: now.subtract(const Duration(days: 3)),
|
||||
),
|
||||
ProductModel(
|
||||
id: 'prod_${_uuid.v4()}',
|
||||
name: 'Blender',
|
||||
description: 'High-power 1000W blender perfect for smoothies and crushing ice',
|
||||
price: 59.99,
|
||||
imageUrl: 'https://picsum.photos/seed/blender/400/400',
|
||||
categoryId: 'cat_appliances',
|
||||
stockQuantity: 12,
|
||||
isAvailable: true,
|
||||
createdAt: now.subtract(const Duration(days: 15)),
|
||||
updatedAt: now.subtract(const Duration(days: 2)),
|
||||
),
|
||||
|
||||
// Sports & Fitness (3 products)
|
||||
ProductModel(
|
||||
id: 'prod_${_uuid.v4()}',
|
||||
name: 'Yoga Mat',
|
||||
description: 'Non-slip exercise yoga mat with carrying strap, 6mm thickness',
|
||||
price: 29.99,
|
||||
imageUrl: 'https://picsum.photos/seed/yogamat/400/400',
|
||||
categoryId: 'cat_sports',
|
||||
stockQuantity: 50,
|
||||
isAvailable: true,
|
||||
createdAt: now.subtract(const Duration(days: 12)),
|
||||
updatedAt: now.subtract(const Duration(days: 1)),
|
||||
),
|
||||
ProductModel(
|
||||
id: 'prod_${_uuid.v4()}',
|
||||
name: 'Running Shoes',
|
||||
description: 'Comfortable running shoes with responsive cushioning and breathable mesh',
|
||||
price: 89.99,
|
||||
imageUrl: 'https://picsum.photos/seed/runningshoes/400/400',
|
||||
categoryId: 'cat_sports',
|
||||
stockQuantity: 30,
|
||||
isAvailable: true,
|
||||
createdAt: now.subtract(const Duration(days: 10)),
|
||||
updatedAt: now.subtract(const Duration(days: 2)),
|
||||
),
|
||||
ProductModel(
|
||||
id: 'prod_${_uuid.v4()}',
|
||||
name: 'Water Bottle',
|
||||
description: 'Insulated stainless steel water bottle, 32oz capacity, keeps cold 24hrs',
|
||||
price: 24.99,
|
||||
imageUrl: 'https://picsum.photos/seed/waterbottle/400/400',
|
||||
categoryId: 'cat_sports',
|
||||
stockQuantity: 45,
|
||||
isAvailable: true,
|
||||
createdAt: now.subtract(const Duration(days: 8)),
|
||||
updatedAt: now,
|
||||
),
|
||||
|
||||
// Fashion (2 products)
|
||||
ProductModel(
|
||||
id: 'prod_${_uuid.v4()}',
|
||||
name: 'Leather Backpack',
|
||||
description: 'Premium leather backpack with laptop compartment and multiple pockets',
|
||||
price: 129.99,
|
||||
imageUrl: 'https://picsum.photos/seed/backpack/400/400',
|
||||
categoryId: 'cat_fashion',
|
||||
stockQuantity: 18,
|
||||
isAvailable: true,
|
||||
createdAt: now.subtract(const Duration(days: 7)),
|
||||
updatedAt: now.subtract(const Duration(days: 1)),
|
||||
),
|
||||
ProductModel(
|
||||
id: 'prod_${_uuid.v4()}',
|
||||
name: 'Sunglasses',
|
||||
description: 'UV protection polarized sunglasses with stylish design',
|
||||
price: 49.99,
|
||||
imageUrl: 'https://picsum.photos/seed/sunglasses/400/400',
|
||||
categoryId: 'cat_fashion',
|
||||
stockQuantity: 35,
|
||||
isAvailable: true,
|
||||
createdAt: now.subtract(const Duration(days: 5)),
|
||||
updatedAt: now.subtract(const Duration(days: 1)),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
/// Seed database with sample data
|
||||
static Future<void> seedDatabase({
|
||||
required Future<void> Function(List<CategoryModel>) saveCategories,
|
||||
required Future<void> Function(List<ProductModel>) saveProducts,
|
||||
}) async {
|
||||
// Generate and save categories
|
||||
final categories = generateCategories();
|
||||
await saveCategories(categories);
|
||||
|
||||
// Generate and save products
|
||||
final products = generateProducts();
|
||||
await saveProducts(products);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user