[storage] refactor to based and main storage [BasedScreen] store storage context as well (will probably create some main dao in future)
This commit is contained in:
		
							parent
							
								
									1100114040
								
							
						
					
					
						commit
						07c92443ce
					
				
					 16 changed files with 151 additions and 122 deletions
				
			
		|  | @ -14,10 +14,12 @@ class ApiClient { | ||||||
| 
 | 
 | ||||||
|   ApiClient({ |   ApiClient({ | ||||||
|     required this.baseUrl, |     required this.baseUrl, | ||||||
|   }) { |   }); | ||||||
|     () async { | 
 | ||||||
|       await loadToken(); |   static Future<ApiClient> create({required String baseUrl}) async { | ||||||
|     }(); |     var client = ApiClient(baseUrl: baseUrl); | ||||||
|  |     client.loadToken(); | ||||||
|  |     return client; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   Future<void> loadToken() async { |   Future<void> loadToken() async { | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								lib/client/based.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								lib/client/based.dart
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | import 'package:fooder/client.dart'; | ||||||
|  | @ -1,10 +1,14 @@ | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:fooder/screens/login.dart'; | import 'package:fooder/screens/login.dart'; | ||||||
| import 'package:fooder/client.dart'; | import 'package:fooder/client.dart'; | ||||||
|  | import 'package:fooder/storage.dart'; | ||||||
| import 'package:fooder/theme.dart'; | import 'package:fooder/theme.dart'; | ||||||
| 
 | 
 | ||||||
| class MyApp extends StatelessWidget { | class MyApp extends StatelessWidget { | ||||||
|   const MyApp({super.key}); |   final Storage storage; | ||||||
|  |   final ApiClient apiClient; | ||||||
|  | 
 | ||||||
|  |   const MyApp({required this.storage, required this.apiClient, super.key}); | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|  | @ -15,14 +19,18 @@ class MyApp extends StatelessWidget { | ||||||
|       themeMode: ThemeMode.system, |       themeMode: ThemeMode.system, | ||||||
|       debugShowCheckedModeBanner: false, |       debugShowCheckedModeBanner: false, | ||||||
|       home: LoginScreen( |       home: LoginScreen( | ||||||
|         apiClient: ApiClient( |         apiClient: apiClient, | ||||||
|           baseUrl: 'https://fooderapi.domandoman.xyz/api', |         storage: storage, | ||||||
|         ), |  | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void main() { | void main() async { | ||||||
|   runApp(const MyApp()); |   var storage = await Storage.create(); | ||||||
|  |   var apiClient = await ApiClient.create( | ||||||
|  |     baseUrl: 'https://fooderapi.domandoman.xyz/api', | ||||||
|  |   ); | ||||||
|  | 
 | ||||||
|  |   runApp(MyApp(storage: storage, apiClient: apiClient)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ class Product { | ||||||
|   final double carb; |   final double carb; | ||||||
|   final double fat; |   final double fat; | ||||||
|   final double fiber; |   final double fiber; | ||||||
|  |   final int usageCountCached; | ||||||
|   final String? barcode; |   final String? barcode; | ||||||
| 
 | 
 | ||||||
|   Product( |   Product( | ||||||
|  | @ -16,6 +17,7 @@ class Product { | ||||||
|       required this.carb, |       required this.carb, | ||||||
|       required this.fat, |       required this.fat, | ||||||
|       required this.fiber, |       required this.fiber, | ||||||
|  |       this.usageCountCached = 0, | ||||||
|       this.barcode}); |       this.barcode}); | ||||||
| 
 | 
 | ||||||
|   Product.fromJson(Map<String, dynamic> map) |   Product.fromJson(Map<String, dynamic> map) | ||||||
|  | @ -26,6 +28,7 @@ class Product { | ||||||
|         carb = map['carb'] as double, |         carb = map['carb'] as double, | ||||||
|         fat = map['fat'] as double, |         fat = map['fat'] as double, | ||||||
|         fiber = map['fiber'] as double, |         fiber = map['fiber'] as double, | ||||||
|  |         usageCountCached = map['usage_count_cached'] as int, | ||||||
|         barcode = map['barcode'] as String?; |         barcode = map['barcode'] as String?; | ||||||
| 
 | 
 | ||||||
|   Map<String, Object?> toMap() { |   Map<String, Object?> toMap() { | ||||||
|  | @ -38,6 +41,7 @@ class Product { | ||||||
|       'fat': fat, |       'fat': fat, | ||||||
|       'fiber': fiber, |       'fiber': fiber, | ||||||
|       'barcode': barcode, |       'barcode': barcode, | ||||||
|  |       'usage_count_cached': usageCountCached, | ||||||
|     }; |     }; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -9,14 +9,16 @@ import 'package:fooder/components/text.dart'; | ||||||
| import 'package:fooder/components/dropdown.dart'; | import 'package:fooder/components/dropdown.dart'; | ||||||
| import 'package:fooder/components/floating_action_button.dart'; | import 'package:fooder/components/floating_action_button.dart'; | ||||||
| import 'package:fooder/screens/add_product.dart'; | import 'package:fooder/screens/add_product.dart'; | ||||||
| import 'package:fooder/storage/base.dart'; |  | ||||||
| import 'package:simple_barcode_scanner/simple_barcode_scanner.dart'; | import 'package:simple_barcode_scanner/simple_barcode_scanner.dart'; | ||||||
| 
 | 
 | ||||||
| class AddEntryScreen extends BasedScreen { | class AddEntryScreen extends BasedScreen { | ||||||
|   final Diary diary; |   final Diary diary; | ||||||
| 
 | 
 | ||||||
|   const AddEntryScreen( |   const AddEntryScreen( | ||||||
|       {super.key, required super.apiClient, required this.diary}); |       {super.key, | ||||||
|  |       required super.apiClient, | ||||||
|  |       required super.storage, | ||||||
|  |       required this.diary}); | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   State<AddEntryScreen> createState() => _AddEntryScreen(); |   State<AddEntryScreen> createState() => _AddEntryScreen(); | ||||||
|  | @ -27,6 +29,7 @@ class _AddEntryScreen extends BasedState<AddEntryScreen> { | ||||||
|   final productNameController = TextEditingController(); |   final productNameController = TextEditingController(); | ||||||
|   Meal? meal; |   Meal? meal; | ||||||
|   List<Product> products = []; |   List<Product> products = []; | ||||||
|  |   Diary get diary => widget.diary; | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   void dispose() { |   void dispose() { | ||||||
|  | @ -45,35 +48,18 @@ class _AddEntryScreen extends BasedState<AddEntryScreen> { | ||||||
|   void initState() { |   void initState() { | ||||||
|     super.initState(); |     super.initState(); | ||||||
|     setState(() { |     setState(() { | ||||||
|       meal = widget.diary.meals[0]; |       meal = diary.meals[0]; | ||||||
|     }); |     }); | ||||||
|     _getProducts().then((value) => null); |     _getProducts().then((value) => null); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   Future<void> _getProducts() async { |   Future<void> _getProducts() async { | ||||||
|     if (storage != null) { |     var productsMap = await apiClient.getProducts(productNameController.text); | ||||||
|       var storagePorducts = await storage!.product.list(); |  | ||||||
| 
 |  | ||||||
|       if (storagePorducts.length > 5) { |  | ||||||
|         print("Using local storage"); |  | ||||||
|         setState(() { |  | ||||||
|           products = storagePorducts; |  | ||||||
|         }); |  | ||||||
|         return; |  | ||||||
|       } |  | ||||||
|     } else { |  | ||||||
|       print("No local storage"); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     var productsMap = |  | ||||||
|         await widget.apiClient.getProducts(productNameController.text); |  | ||||||
| 
 | 
 | ||||||
|     var parsedProducts = (productsMap['products'] as List<dynamic>) |     var parsedProducts = (productsMap['products'] as List<dynamic>) | ||||||
|         .map((e) => Product.fromJson(e as Map<String, dynamic>)) |         .map((e) => Product.fromJson(e as Map<String, dynamic>)) | ||||||
|         .toList(); |         .toList(); | ||||||
| 
 | 
 | ||||||
|     await storage!.product.bulkInsert(parsedProducts); |  | ||||||
| 
 |  | ||||||
|     setState(() { |     setState(() { | ||||||
|       products = parsedProducts; |       products = parsedProducts; | ||||||
|     }); |     }); | ||||||
|  | @ -113,7 +99,7 @@ class _AddEntryScreen extends BasedState<AddEntryScreen> { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     await widget.apiClient.addEntry( |     await apiClient.addEntry( | ||||||
|       grams: grams, |       grams: grams, | ||||||
|       productId: products[0].id, |       productId: products[0].id, | ||||||
|       mealId: meal!.id, |       mealId: meal!.id, | ||||||
|  | @ -131,7 +117,7 @@ class _AddEntryScreen extends BasedState<AddEntryScreen> { | ||||||
| 
 | 
 | ||||||
|     if (res is String) { |     if (res is String) { | ||||||
|       try { |       try { | ||||||
|         var productMap = await widget.apiClient.getProductByBarcode(res); |         var productMap = await apiClient.getProductByBarcode(res); | ||||||
| 
 | 
 | ||||||
|         var product = Product.fromJson(productMap); |         var product = Product.fromJson(productMap); | ||||||
| 
 | 
 | ||||||
|  | @ -168,7 +154,7 @@ class _AddEntryScreen extends BasedState<AddEntryScreen> { | ||||||
|                   }); |                   }); | ||||||
|                 }, |                 }, | ||||||
|                 items: <DropdownMenuItem<Meal>>[ |                 items: <DropdownMenuItem<Meal>>[ | ||||||
|                   for (var meal in widget.diary.meals) |                   for (var meal in diary.meals) | ||||||
|                     DropdownMenuItem<Meal>( |                     DropdownMenuItem<Meal>( | ||||||
|                       value: meal, |                       value: meal, | ||||||
|                       child: Text(meal.name), |                       child: Text(meal.name), | ||||||
|  | @ -199,7 +185,8 @@ class _AddEntryScreen extends BasedState<AddEntryScreen> { | ||||||
|                     context, |                     context, | ||||||
|                     MaterialPageRoute( |                     MaterialPageRoute( | ||||||
|                       builder: (context) => AddProductScreen( |                       builder: (context) => AddProductScreen( | ||||||
|                         apiClient: widget.apiClient, |                         apiClient: apiClient, | ||||||
|  |                         storage: storage, | ||||||
|                       ), |                       ), | ||||||
|                     ), |                     ), | ||||||
|                   ).then((product) { |                   ).then((product) { | ||||||
|  |  | ||||||
|  | @ -10,7 +10,10 @@ class AddMealScreen extends BasedScreen { | ||||||
|   final Diary diary; |   final Diary diary; | ||||||
| 
 | 
 | ||||||
|   const AddMealScreen( |   const AddMealScreen( | ||||||
|       {super.key, required super.apiClient, required this.diary}); |       {super.key, | ||||||
|  |       required super.apiClient, | ||||||
|  |       required super.storage, | ||||||
|  |       required this.diary}); | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   State<AddMealScreen> createState() => _AddMealScreen(); |   State<AddMealScreen> createState() => _AddMealScreen(); | ||||||
|  | @ -22,10 +25,10 @@ class _AddMealScreen extends BasedState<AddMealScreen> { | ||||||
|   bool nameChanged = false; |   bool nameChanged = false; | ||||||
|   List<Preset> presets = []; |   List<Preset> presets = []; | ||||||
|   Preset? selectedPreset; |   Preset? selectedPreset; | ||||||
|  |   Diary get diary => widget.diary; | ||||||
| 
 | 
 | ||||||
|   Future<void> _getPresets() async { |   Future<void> _getPresets() async { | ||||||
|     var presetsMap = |     var presetsMap = await apiClient.getPresets(presetNameController.text); | ||||||
|         await widget.apiClient.getPresets(presetNameController.text); |  | ||||||
| 
 | 
 | ||||||
|     setState(() { |     setState(() { | ||||||
|       presets = (presetsMap['presets'] as List<dynamic>) |       presets = (presetsMap['presets'] as List<dynamic>) | ||||||
|  | @ -39,7 +42,7 @@ class _AddMealScreen extends BasedState<AddMealScreen> { | ||||||
|   void initState() { |   void initState() { | ||||||
|     super.initState(); |     super.initState(); | ||||||
|     setState(() { |     setState(() { | ||||||
|       nameController.text = "Meal ${widget.diary.meals.length + 1}"; |       nameController.text = "Meal ${diary.meals.length + 1}"; | ||||||
|     }); |     }); | ||||||
|     _getPresets(); |     _getPresets(); | ||||||
|   } |   } | ||||||
|  | @ -57,15 +60,15 @@ class _AddMealScreen extends BasedState<AddMealScreen> { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   Future<void> _addMeal() async { |   Future<void> _addMeal() async { | ||||||
|     await widget.apiClient.addMeal( |     await apiClient.addMeal( | ||||||
|       name: nameController.text, |       name: nameController.text, | ||||||
|       diaryId: widget.diary.id, |       diaryId: diary.id, | ||||||
|     ); |     ); | ||||||
|     popMeDaddy(); |     popMeDaddy(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   Future<void> _deletePreset(Preset preset) async { |   Future<void> _deletePreset(Preset preset) async { | ||||||
|     widget.apiClient.deletePreset(preset.id); |     apiClient.deletePreset(preset.id); | ||||||
|     setState(() { |     setState(() { | ||||||
|       presets.remove(preset); |       presets.remove(preset); | ||||||
|     }); |     }); | ||||||
|  | @ -103,9 +106,9 @@ class _AddMealScreen extends BasedState<AddMealScreen> { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     await widget.apiClient.addMealFromPreset( |     await apiClient.addMealFromPreset( | ||||||
|       name: nameChanged ? nameController.text : selectedPreset!.name, |       name: nameChanged ? nameController.text : selectedPreset!.name, | ||||||
|       diaryId: widget.diary.id, |       diaryId: diary.id, | ||||||
|       presetId: selectedPreset!.id, |       presetId: selectedPreset!.id, | ||||||
|     ); |     ); | ||||||
|     popMeDaddy(); |     popMeDaddy(); | ||||||
|  |  | ||||||
|  | @ -7,7 +7,8 @@ import 'package:fooder/components/text.dart'; | ||||||
| import 'package:fooder/components/floating_action_button.dart'; | import 'package:fooder/components/floating_action_button.dart'; | ||||||
| 
 | 
 | ||||||
| class AddProductScreen extends BasedScreen { | class AddProductScreen extends BasedScreen { | ||||||
|   const AddProductScreen({super.key, required super.apiClient}); |   const AddProductScreen( | ||||||
|  |       {super.key, required super.apiClient, required super.storage}); | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   State<AddProductScreen> createState() => _AddProductScreen(); |   State<AddProductScreen> createState() => _AddProductScreen(); | ||||||
|  | @ -61,7 +62,7 @@ class _AddProductScreen extends BasedState<AddProductScreen> { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     try { |     try { | ||||||
|       var productJson = await widget.apiClient.addProduct( |       var productJson = await apiClient.addProduct( | ||||||
|         carb: carb, |         carb: carb, | ||||||
|         fat: fat, |         fat: fat, | ||||||
|         protein: protein, |         protein: protein, | ||||||
|  |  | ||||||
|  | @ -1,10 +1,10 @@ | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:fooder/client.dart'; | import 'package:fooder/client.dart'; | ||||||
|  | import 'package:fooder/storage.dart'; | ||||||
| import 'package:fooder/components/app_bar.dart'; | import 'package:fooder/components/app_bar.dart'; | ||||||
| import 'package:fooder/components/navigation_bar.dart'; | import 'package:fooder/components/navigation_bar.dart'; | ||||||
| import 'package:fooder/screens/login.dart'; | import 'package:fooder/screens/login.dart'; | ||||||
| import 'package:fooder/screens/main.dart'; | import 'package:fooder/screens/main.dart'; | ||||||
| import 'package:fooder/storage/base.dart'; |  | ||||||
| 
 | 
 | ||||||
| TextStyle logoStyle(context) { | TextStyle logoStyle(context) { | ||||||
|   return Theme.of(context).textTheme.labelLarge!.copyWith( |   return Theme.of(context).textTheme.labelLarge!.copyWith( | ||||||
|  | @ -14,34 +14,27 @@ TextStyle logoStyle(context) { | ||||||
| 
 | 
 | ||||||
| abstract class BasedScreen extends StatefulWidget { | abstract class BasedScreen extends StatefulWidget { | ||||||
|   final ApiClient apiClient; |   final ApiClient apiClient; | ||||||
|   final Storage? storage; |   final Storage storage; | ||||||
| 
 | 
 | ||||||
|   const BasedScreen({super.key, required this.apiClient, this.storage}); |   const BasedScreen( | ||||||
|  |       {super.key, required this.apiClient, required this.storage}); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| abstract class BasedState<T extends BasedScreen> extends State<T> { | abstract class BasedState<T extends BasedScreen> extends State<T> { | ||||||
|   Storage? storage; |   ApiClient get apiClient => widget.apiClient; | ||||||
|  |   Storage get storage => widget.storage; | ||||||
| 
 | 
 | ||||||
|   @override |   void logout() async { | ||||||
|   void initState() { |     await apiClient.logout(); | ||||||
|     super.initState(); |     backToLogin(); | ||||||
|     _asyncInitState().then((value) => null); |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   Future<void> _asyncInitState() async { |   void backToLogin() { | ||||||
|     if (widget.storage != null) { |  | ||||||
|       this.storage = widget.storage; |  | ||||||
|     } else { |  | ||||||
|       this.storage = await Storage.create(); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   void _logout() async { |  | ||||||
|     await widget.apiClient.logout(); |  | ||||||
|     Navigator.pushReplacement( |     Navigator.pushReplacement( | ||||||
|       context, |       context, | ||||||
|       MaterialPageRoute( |       MaterialPageRoute( | ||||||
|         builder: (context) => LoginScreen(apiClient: widget.apiClient), |         builder: (context) => | ||||||
|  |             LoginScreen(apiClient: apiClient, storage: storage), | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  | @ -50,7 +43,8 @@ abstract class BasedState<T extends BasedScreen> extends State<T> { | ||||||
|     Navigator.pushReplacement( |     Navigator.pushReplacement( | ||||||
|       context, |       context, | ||||||
|       MaterialPageRoute( |       MaterialPageRoute( | ||||||
|         builder: (context) => MainScreen(apiClient: widget.apiClient), |         builder: (context) => | ||||||
|  |             MainScreen(apiClient: apiClient, storage: storage), | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  | @ -63,7 +57,7 @@ abstract class BasedState<T extends BasedScreen> extends State<T> { | ||||||
|             Icons.logout, |             Icons.logout, | ||||||
|             color: Theme.of(context).colorScheme.onSurfaceVariant, |             color: Theme.of(context).colorScheme.onSurfaceVariant, | ||||||
|           ), |           ), | ||||||
|           onPressed: _logout, |           onPressed: logout, | ||||||
|         ), |         ), | ||||||
|       ], |       ], | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|  | @ -13,7 +13,10 @@ class EditEntryScreen extends BasedScreen { | ||||||
|   final Entry entry; |   final Entry entry; | ||||||
| 
 | 
 | ||||||
|   const EditEntryScreen( |   const EditEntryScreen( | ||||||
|       {super.key, required super.apiClient, required this.entry}); |       {super.key, | ||||||
|  |       required super.apiClient, | ||||||
|  |       required super.storage, | ||||||
|  |       required this.entry}); | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   State<EditEntryScreen> createState() => _EditEntryScreen(); |   State<EditEntryScreen> createState() => _EditEntryScreen(); | ||||||
|  | @ -23,6 +26,7 @@ class _EditEntryScreen extends BasedState<EditEntryScreen> { | ||||||
|   final gramsController = TextEditingController(); |   final gramsController = TextEditingController(); | ||||||
|   final productNameController = TextEditingController(); |   final productNameController = TextEditingController(); | ||||||
|   List<Product> products = []; |   List<Product> products = []; | ||||||
|  |   Entry get entry => entry; | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   void dispose() { |   void dispose() { | ||||||
|  | @ -39,15 +43,14 @@ class _EditEntryScreen extends BasedState<EditEntryScreen> { | ||||||
|   void initState() { |   void initState() { | ||||||
|     super.initState(); |     super.initState(); | ||||||
|     setState(() { |     setState(() { | ||||||
|       gramsController.text = widget.entry.grams.toString(); |       gramsController.text = entry.grams.toString(); | ||||||
|       productNameController.text = widget.entry.product.name; |       productNameController.text = entry.product.name; | ||||||
|       products = [widget.entry.product]; |       products = [entry.product]; | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   Future<void> _getProducts() async { |   Future<void> _getProducts() async { | ||||||
|     var productsMap = |     var productsMap = await apiClient.getProducts(productNameController.text); | ||||||
|         await widget.apiClient.getProducts(productNameController.text); |  | ||||||
|     setState(() { |     setState(() { | ||||||
|       products = (productsMap['products'] as List<dynamic>) |       products = (productsMap['products'] as List<dynamic>) | ||||||
|           .map((e) => Product.fromJson(e as Map<String, dynamic>)) |           .map((e) => Product.fromJson(e as Map<String, dynamic>)) | ||||||
|  | @ -75,17 +78,17 @@ class _EditEntryScreen extends BasedState<EditEntryScreen> { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     await widget.apiClient.updateEntry( |     await apiClient.updateEntry( | ||||||
|       widget.entry.id, |       entry.id, | ||||||
|       grams: grams, |       grams: grams, | ||||||
|       productId: products[0].id, |       productId: products[0].id, | ||||||
|       mealId: widget.entry.mealId, |       mealId: entry.mealId, | ||||||
|     ); |     ); | ||||||
|     popMeDaddy(); |     popMeDaddy(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   Future<void> _deleteEntry() async { |   Future<void> _deleteEntry() async { | ||||||
|     await widget.apiClient.deleteEntry(widget.entry.id); |     await apiClient.deleteEntry(widget.entry.id); | ||||||
|     popMeDaddy(); |     popMeDaddy(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -99,7 +102,7 @@ class _EditEntryScreen extends BasedState<EditEntryScreen> { | ||||||
| 
 | 
 | ||||||
|     if (res is String) { |     if (res is String) { | ||||||
|       try { |       try { | ||||||
|         var productMap = await widget.apiClient.getProductByBarcode(res); |         var productMap = await apiClient.getProductByBarcode(res); | ||||||
| 
 | 
 | ||||||
|         var product = Product.fromJson(productMap); |         var product = Product.fromJson(productMap); | ||||||
| 
 | 
 | ||||||
|  | @ -144,7 +147,8 @@ class _EditEntryScreen extends BasedState<EditEntryScreen> { | ||||||
|                     context, |                     context, | ||||||
|                     MaterialPageRoute( |                     MaterialPageRoute( | ||||||
|                       builder: (context) => AddProductScreen( |                       builder: (context) => AddProductScreen( | ||||||
|                         apiClient: widget.apiClient, |                         apiClient: apiClient, | ||||||
|  |                         storage: storage, | ||||||
|                       ), |                       ), | ||||||
|                     ), |                     ), | ||||||
|                   ).then((product) { |                   ).then((product) { | ||||||
|  |  | ||||||
|  | @ -7,7 +7,8 @@ import 'package:fooder/components/text.dart'; | ||||||
| import 'package:fooder/components/button.dart'; | import 'package:fooder/components/button.dart'; | ||||||
| 
 | 
 | ||||||
| class LoginScreen extends BasedScreen { | class LoginScreen extends BasedScreen { | ||||||
|   const LoginScreen({super.key, required super.apiClient}); |   const LoginScreen( | ||||||
|  |       {super.key, required super.apiClient, required super.storage}); | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   State<LoginScreen> createState() => _LoginScreen(); |   State<LoginScreen> createState() => _LoginScreen(); | ||||||
|  | @ -28,7 +29,8 @@ class _LoginScreen extends BasedState<LoginScreen> { | ||||||
|     Navigator.pushReplacement( |     Navigator.pushReplacement( | ||||||
|       context, |       context, | ||||||
|       MaterialPageRoute( |       MaterialPageRoute( | ||||||
|         builder: (context) => MainScreen(apiClient: widget.apiClient), |         builder: (context) => | ||||||
|  |             MainScreen(apiClient: apiClient, storage: storage), | ||||||
|       ), |       ), | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  | @ -36,7 +38,7 @@ class _LoginScreen extends BasedState<LoginScreen> { | ||||||
|   // login client when button pressed |   // login client when button pressed | ||||||
|   Future<void> _login() async { |   Future<void> _login() async { | ||||||
|     try { |     try { | ||||||
|       await widget.apiClient.login( |       await apiClient.login( | ||||||
|         usernameController.text, |         usernameController.text, | ||||||
|         passwordController.text, |         passwordController.text, | ||||||
|       ); |       ); | ||||||
|  | @ -62,14 +64,14 @@ class _LoginScreen extends BasedState<LoginScreen> { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   Future<void> _asyncInitState() async { |   Future<void> _asyncInitState() async { | ||||||
|     await widget.apiClient.loadToken(); |     await apiClient.loadToken(); | ||||||
| 
 | 
 | ||||||
|     if (widget.apiClient.refreshToken == null) { |     if (apiClient.refreshToken == null) { | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     try { |     try { | ||||||
|       await widget.apiClient.refresh(); |       await apiClient.refresh(); | ||||||
|       showText("Welcome back!"); |       showText("Welcome back!"); | ||||||
|       popMeDaddy(); |       popMeDaddy(); | ||||||
|     } on Exception catch (_) { |     } on Exception catch (_) { | ||||||
|  | @ -120,8 +122,10 @@ class _LoginScreen extends BasedState<LoginScreen> { | ||||||
|                       Navigator.push( |                       Navigator.push( | ||||||
|                         context, |                         context, | ||||||
|                         MaterialPageRoute( |                         MaterialPageRoute( | ||||||
|                           builder: (context) => |                           builder: (context) => RegisterScreen( | ||||||
|                               RegisterScreen(apiClient: widget.apiClient), |                             apiClient: apiClient, | ||||||
|  |                             storage: storage, | ||||||
|  |                           ), | ||||||
|                         ), |                         ), | ||||||
|                       ); |                       ); | ||||||
|                     }, |                     }, | ||||||
|  |  | ||||||
|  | @ -8,10 +8,10 @@ import 'package:fooder/widgets/meal.dart'; | ||||||
| import 'package:fooder/components/sliver.dart'; | import 'package:fooder/components/sliver.dart'; | ||||||
| import 'package:fooder/components/date_picker.dart'; | import 'package:fooder/components/date_picker.dart'; | ||||||
| import 'package:fooder/components/floating_action_button.dart'; | import 'package:fooder/components/floating_action_button.dart'; | ||||||
| import 'package:fooder/storage/base.dart'; |  | ||||||
| 
 | 
 | ||||||
| class MainScreen extends BasedScreen { | class MainScreen extends BasedScreen { | ||||||
|   const MainScreen({super.key, required super.apiClient}); |   const MainScreen( | ||||||
|  |       {super.key, required super.apiClient, required super.storage}); | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   State<MainScreen> createState() => _MainScreen(); |   State<MainScreen> createState() => _MainScreen(); | ||||||
|  | @ -28,7 +28,7 @@ class _MainScreen extends BasedState<MainScreen> { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   Future<void> _asyncInitState() async { |   Future<void> _asyncInitState() async { | ||||||
|     var diaryMap = await widget.apiClient.getDiary(date: date); |     var diaryMap = await apiClient.getDiary(date: date); | ||||||
| 
 | 
 | ||||||
|     setState(() { |     setState(() { | ||||||
|       diary = Diary.fromJson(diaryMap); |       diary = Diary.fromJson(diaryMap); | ||||||
|  | @ -52,8 +52,8 @@ class _MainScreen extends BasedState<MainScreen> { | ||||||
|     await Navigator.push( |     await Navigator.push( | ||||||
|       context, |       context, | ||||||
|       MaterialPageRoute( |       MaterialPageRoute( | ||||||
|         builder: (context) => |         builder: (context) => AddEntryScreen( | ||||||
|             AddEntryScreen(apiClient: widget.apiClient, diary: diary!), |             apiClient: apiClient, diary: diary!, storage: storage), | ||||||
|       ), |       ), | ||||||
|     ).then((_) => _asyncInitState()); |     ).then((_) => _asyncInitState()); | ||||||
|   } |   } | ||||||
|  | @ -67,8 +67,9 @@ class _MainScreen extends BasedState<MainScreen> { | ||||||
|       context, |       context, | ||||||
|       MaterialPageRoute( |       MaterialPageRoute( | ||||||
|         builder: (context) => AddMealScreen( |         builder: (context) => AddMealScreen( | ||||||
|           apiClient: widget.apiClient, |           apiClient: apiClient, | ||||||
|           diary: diary!, |           diary: diary!, | ||||||
|  |           storage: storage, | ||||||
|         ), |         ), | ||||||
|       ), |       ), | ||||||
|     ).then((_) => _asyncInitState()); |     ).then((_) => _asyncInitState()); | ||||||
|  | @ -90,13 +91,14 @@ class _MainScreen extends BasedState<MainScreen> { | ||||||
|             [ |             [ | ||||||
|               SummaryWidget( |               SummaryWidget( | ||||||
|                 diary: diary!, |                 diary: diary!, | ||||||
|                 apiClient: widget.apiClient, |                 apiClient: apiClient, | ||||||
|                 refreshParent: _asyncInitState, |                 refreshParent: _asyncInitState, | ||||||
|               ), |               ), | ||||||
|               for (var (i, meal) in diary!.meals.indexed) |               for (var (i, meal) in diary!.meals.indexed) | ||||||
|                 MealWidget( |                 MealWidget( | ||||||
|  |                   apiClient: apiClient, | ||||||
|  |                   storage: storage, | ||||||
|                   meal: meal, |                   meal: meal, | ||||||
|                   apiClient: widget.apiClient, |  | ||||||
|                   refreshParent: _asyncInitState, |                   refreshParent: _asyncInitState, | ||||||
|                   initiallyExpanded: i == 0, |                   initiallyExpanded: i == 0, | ||||||
|                   showText: showText, |                   showText: showText, | ||||||
|  |  | ||||||
|  | @ -5,7 +5,8 @@ import 'package:fooder/components/text.dart'; | ||||||
| import 'package:fooder/components/button.dart'; | import 'package:fooder/components/button.dart'; | ||||||
| 
 | 
 | ||||||
| class RegisterScreen extends BasedScreen { | class RegisterScreen extends BasedScreen { | ||||||
|   const RegisterScreen({super.key, required super.apiClient}); |   const RegisterScreen( | ||||||
|  |       {super.key, required super.apiClient, required super.storage}); | ||||||
| 
 | 
 | ||||||
|   @override |   @override | ||||||
|   State<RegisterScreen> createState() => _RegisterScreen(); |   State<RegisterScreen> createState() => _RegisterScreen(); | ||||||
|  | @ -49,7 +50,7 @@ class _RegisterScreen extends BasedState<RegisterScreen> { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     try { |     try { | ||||||
|       await widget.apiClient.register( |       await apiClient.register( | ||||||
|         usernameController.text, |         usernameController.text, | ||||||
|         passwordController.text, |         passwordController.text, | ||||||
|       ); |       ); | ||||||
|  |  | ||||||
|  | @ -9,23 +9,23 @@ class Storage { | ||||||
|   Database db; |   Database db; | ||||||
|   ProductStorage product; |   ProductStorage product; | ||||||
| 
 | 
 | ||||||
|  |   static const String path = "storage.db"; | ||||||
|  | 
 | ||||||
|   Storage({required this.db, required this.product}); |   Storage({required this.db, required this.product}); | ||||||
| 
 | 
 | ||||||
|   static Future<Storage> create() async { |   static Future<Storage> create() async { | ||||||
|     var db = await database(); |  | ||||||
|     return Storage(db: db, product: ProductStorage(db: db)); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   static Future<void> createTables(Database db, int version) async { |  | ||||||
|     await ProductStorage.createTable(db, version); |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   static Future<Database> database({String path = "storage.db"}) async { |  | ||||||
|     WidgetsFlutterBinding.ensureInitialized(); |     WidgetsFlutterBinding.ensureInitialized(); | ||||||
|     return openDatabase( |     var db = await openDatabase( | ||||||
|       join(await getDatabasesPath(), path), |       join(await getDatabasesPath(), path), | ||||||
|       onCreate: createTables, |       onCreate: createTables, | ||||||
|       version: 1, |       version: 1, | ||||||
|     ); |     ); | ||||||
|  |     return Storage(db: db, product: ProductStorage(db: db)); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   static Future<void> createTables(Database db, int version) async { | ||||||
|  |     var batch = db.batch(); | ||||||
|  |     await ProductStorage.createTable(batch); | ||||||
|  |     await batch.commit(noResult: true); | ||||||
|   } |   } | ||||||
| } | } | ||||||
							
								
								
									
										11
									
								
								lib/storage/based.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								lib/storage/based.dart
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,11 @@ | ||||||
|  | import 'dart:async'; | ||||||
|  | 
 | ||||||
|  | import 'package:sqflite/sqflite.dart'; | ||||||
|  | 
 | ||||||
|  | abstract class StorageBased { | ||||||
|  |   Database db; | ||||||
|  | 
 | ||||||
|  |   StorageBased({required this.db}); | ||||||
|  | 
 | ||||||
|  |   static Future<void> createTable(Batch batch) async {} | ||||||
|  | } | ||||||
|  | @ -2,29 +2,32 @@ import 'dart:async'; | ||||||
| 
 | 
 | ||||||
| import 'package:sqflite/sqflite.dart'; | import 'package:sqflite/sqflite.dart'; | ||||||
| import 'package:fooder/models/product.dart'; | import 'package:fooder/models/product.dart'; | ||||||
|  | import 'package:fooder/storage/based.dart'; | ||||||
| 
 | 
 | ||||||
| class ProductStorage { | class ProductStorage extends StorageBased { | ||||||
|   Database db; |   ProductStorage({required super.db}); | ||||||
| 
 | 
 | ||||||
|   ProductStorage({required this.db}); |   static Future<void> createTable(Batch batch) async { | ||||||
| 
 |     batch.execute(''' | ||||||
|   static Future<void> createTable(Database db, int version) async { |  | ||||||
|     await db.execute(''' |  | ||||||
|       CREATE TABLE product( |       CREATE TABLE product( | ||||||
|         id INTEGER PRIMARY KEY, |         id INTEGER, | ||||||
|         name TEXT NOT NULL, |         name TEXT, | ||||||
|         barcode TEXT, |         barcode TEXT, | ||||||
|         calories  NOT NULL, |         calories REAL, | ||||||
|         protein REAL NOT NULL, |         protein REAL, | ||||||
|         carb REAL NOT NULL, |         carb REAL, | ||||||
|         fat REAL NOT NULL, |         fat REAL, | ||||||
|         fiber REAL NOT NULL |         fiber REAL, | ||||||
|  |         usage_count_cached INTEGER | ||||||
|       ) |       ) | ||||||
|     '''); |     '''); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   Future<List<Product>> list() async { |   Future<List<Product>> list({String? name, String? barcode}) async { | ||||||
|     var result = await db.query('product'); |     var result = await db.query('product', | ||||||
|  |         where: 'name LIKE ? AND barcode LIKE ?', | ||||||
|  |         whereArgs: ['%$name%', '%$barcode%'], | ||||||
|  |         orderBy: 'usage_count_cached DESC'); | ||||||
|     return result.map((e) => Product.fromJson(e)).toList(); |     return result.map((e) => Product.fromJson(e)).toList(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -4,6 +4,7 @@ import 'package:fooder/widgets/entry.dart'; | ||||||
| import 'package:fooder/widgets/macro.dart'; | import 'package:fooder/widgets/macro.dart'; | ||||||
| import 'package:fooder/screens/edit_entry.dart'; | import 'package:fooder/screens/edit_entry.dart'; | ||||||
| import 'package:fooder/client.dart'; | import 'package:fooder/client.dart'; | ||||||
|  | import 'package:fooder/storage.dart'; | ||||||
| import 'dart:core'; | import 'dart:core'; | ||||||
| 
 | 
 | ||||||
| class MealHeader extends StatelessWidget { | class MealHeader extends StatelessWidget { | ||||||
|  | @ -38,6 +39,7 @@ class MealWidget extends StatelessWidget { | ||||||
| 
 | 
 | ||||||
|   final Meal meal; |   final Meal meal; | ||||||
|   final ApiClient apiClient; |   final ApiClient apiClient; | ||||||
|  |   final Storage storage; | ||||||
|   final Function() refreshParent; |   final Function() refreshParent; | ||||||
|   final Function(String) showText; |   final Function(String) showText; | ||||||
|   final bool initiallyExpanded; |   final bool initiallyExpanded; | ||||||
|  | @ -49,6 +51,7 @@ class MealWidget extends StatelessWidget { | ||||||
|     required this.refreshParent, |     required this.refreshParent, | ||||||
|     required this.initiallyExpanded, |     required this.initiallyExpanded, | ||||||
|     required this.showText, |     required this.showText, | ||||||
|  |     required this.storage, | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   Future<void> saveMeal(context) async { |   Future<void> saveMeal(context) async { | ||||||
|  | @ -124,6 +127,7 @@ class MealWidget extends StatelessWidget { | ||||||
|         builder: (context) => EditEntryScreen( |         builder: (context) => EditEntryScreen( | ||||||
|           apiClient: apiClient, |           apiClient: apiClient, | ||||||
|           entry: entry, |           entry: entry, | ||||||
|  |           storage: storage, | ||||||
|         ), |         ), | ||||||
|       ), |       ), | ||||||
|     ).then((_) => refreshParent()); |     ).then((_) => refreshParent()); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue