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