[format]
This commit is contained in:
		
							parent
							
								
									6d7613c5ff
								
							
						
					
					
						commit
						072ef2f963
					
				
					 19 changed files with 285 additions and 283 deletions
				
			
		| 
						 | 
					@ -3,7 +3,6 @@ import 'dart:convert';
 | 
				
			||||||
import 'dart:html';
 | 
					import 'dart:html';
 | 
				
			||||||
import 'package:intl/intl.dart';
 | 
					import 'package:intl/intl.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class ApiClient {
 | 
					class ApiClient {
 | 
				
			||||||
  final String baseUrl;
 | 
					  final String baseUrl;
 | 
				
			||||||
  String? token;
 | 
					  String? token;
 | 
				
			||||||
| 
						 | 
					@ -67,7 +66,8 @@ class ApiClient {
 | 
				
			||||||
    return _jsonDecode(response);
 | 
					    return _jsonDecode(response);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<Map<String, dynamic>> post(String path, Map<String, dynamic> body, {bool forLogin = false}) async {
 | 
					  Future<Map<String, dynamic>> post(String path, Map<String, dynamic> body,
 | 
				
			||||||
 | 
					      {bool forLogin = false}) async {
 | 
				
			||||||
    final response = await httpClient.post(
 | 
					    final response = await httpClient.post(
 | 
				
			||||||
      Uri.parse('$baseUrl$path'),
 | 
					      Uri.parse('$baseUrl$path'),
 | 
				
			||||||
      body: jsonEncode(body),
 | 
					      body: jsonEncode(body),
 | 
				
			||||||
| 
						 | 
					@ -86,7 +86,6 @@ class ApiClient {
 | 
				
			||||||
    return _jsonDecode(response);
 | 
					    return _jsonDecode(response);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
  Future<void> delete(String path) async {
 | 
					  Future<void> delete(String path) async {
 | 
				
			||||||
    final response = await httpClient.delete(
 | 
					    final response = await httpClient.delete(
 | 
				
			||||||
      Uri.parse('$baseUrl$path'),
 | 
					      Uri.parse('$baseUrl$path'),
 | 
				
			||||||
| 
						 | 
					@ -103,7 +102,8 @@ class ApiClient {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<Map<String, dynamic>> patch(String path, Map<String, dynamic> body) async {
 | 
					  Future<Map<String, dynamic>> patch(
 | 
				
			||||||
 | 
					      String path, Map<String, dynamic> body) async {
 | 
				
			||||||
    final response = await httpClient.patch(
 | 
					    final response = await httpClient.patch(
 | 
				
			||||||
      Uri.parse('$baseUrl$path'),
 | 
					      Uri.parse('$baseUrl$path'),
 | 
				
			||||||
      body: jsonEncode(body),
 | 
					      body: jsonEncode(body),
 | 
				
			||||||
| 
						 | 
					@ -140,7 +140,7 @@ class ApiClient {
 | 
				
			||||||
    if (response.statusCode != 200) {
 | 
					    if (response.statusCode != 200) {
 | 
				
			||||||
      throw Exception('Failed to login');
 | 
					      throw Exception('Failed to login');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    final token = _jsonDecode(response)['access_token'];
 | 
					    final token = _jsonDecode(response)['access_token'];
 | 
				
			||||||
    this.token = token;
 | 
					    this.token = token;
 | 
				
			||||||
    window.localStorage['token'] = token;
 | 
					    window.localStorage['token'] = token;
 | 
				
			||||||
| 
						 | 
					@ -155,12 +155,9 @@ class ApiClient {
 | 
				
			||||||
      throw Exception("No valid refresh token found");
 | 
					      throw Exception("No valid refresh token found");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    final response = await post(
 | 
					    final response = await post("/token/refresh", {
 | 
				
			||||||
      "/token/refresh",
 | 
					      "refresh_token": refreshToken,
 | 
				
			||||||
      {
 | 
					    });
 | 
				
			||||||
        "refresh_token": refreshToken,
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    token = response['access_token'] as String;
 | 
					    token = response['access_token'] as String;
 | 
				
			||||||
    window.localStorage['token'] = token!;
 | 
					    window.localStorage['token'] = token!;
 | 
				
			||||||
| 
						 | 
					@ -185,7 +182,8 @@ class ApiClient {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<Map<String, dynamic>> getProducts(String q) async {
 | 
					  Future<Map<String, dynamic>> getProducts(String q) async {
 | 
				
			||||||
    var response = await get("/product?${Uri(queryParameters: {"q": q}).query}");
 | 
					    var response =
 | 
				
			||||||
 | 
					        await get("/product?${Uri(queryParameters: {"q": q}).query}");
 | 
				
			||||||
    return response;
 | 
					    return response;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -193,8 +191,7 @@ class ApiClient {
 | 
				
			||||||
    required double grams,
 | 
					    required double grams,
 | 
				
			||||||
    required int productId,
 | 
					    required int productId,
 | 
				
			||||||
    required int mealId,
 | 
					    required int mealId,
 | 
				
			||||||
  }
 | 
					  }) async {
 | 
				
			||||||
  ) async {
 | 
					 | 
				
			||||||
    var entry = {
 | 
					    var entry = {
 | 
				
			||||||
      "grams": grams,
 | 
					      "grams": grams,
 | 
				
			||||||
      "product_id": productId,
 | 
					      "product_id": productId,
 | 
				
			||||||
| 
						 | 
					@ -207,12 +204,12 @@ class ApiClient {
 | 
				
			||||||
    await delete("/entry/$id");
 | 
					    await delete("/entry/$id");
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<void> updateEntry(int id, {
 | 
					  Future<void> updateEntry(
 | 
				
			||||||
 | 
					    int id, {
 | 
				
			||||||
    required double grams,
 | 
					    required double grams,
 | 
				
			||||||
    required int productId,
 | 
					    required int productId,
 | 
				
			||||||
    required int mealId,
 | 
					    required int mealId,
 | 
				
			||||||
  }
 | 
					  }) async {
 | 
				
			||||||
  ) async {
 | 
					 | 
				
			||||||
    var entry = {
 | 
					    var entry = {
 | 
				
			||||||
      "grams": grams,
 | 
					      "grams": grams,
 | 
				
			||||||
      "product_id": productId,
 | 
					      "product_id": productId,
 | 
				
			||||||
| 
						 | 
					@ -223,7 +220,9 @@ class ApiClient {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<void> register(String username, String password) async {
 | 
					  Future<void> register(String username, String password) async {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      await post("/user", {
 | 
					      await post(
 | 
				
			||||||
 | 
					        "/user",
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
          "username": username,
 | 
					          "username": username,
 | 
				
			||||||
          "password": password,
 | 
					          "password": password,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
| 
						 | 
					@ -234,7 +233,8 @@ class ApiClient {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<void> addMeal({required String name, required int diaryId, required int order}) async {
 | 
					  Future<void> addMeal(
 | 
				
			||||||
 | 
					      {required String name, required int diaryId, required int order}) async {
 | 
				
			||||||
    await post("/meal", {
 | 
					    await post("/meal", {
 | 
				
			||||||
      "name": name,
 | 
					      "name": name,
 | 
				
			||||||
      "diary_id": diaryId,
 | 
					      "diary_id": diaryId,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,6 @@ 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';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class MyApp extends StatelessWidget {
 | 
					class MyApp extends StatelessWidget {
 | 
				
			||||||
  const MyApp({super.key});
 | 
					  const MyApp({super.key});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,7 +25,6 @@ class MyApp extends StatelessWidget {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
void main() {
 | 
					void main() {
 | 
				
			||||||
  runApp(const MyApp());
 | 
					  runApp(const MyApp());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,5 @@
 | 
				
			||||||
import 'package:fooder/models/meal.dart';
 | 
					import 'package:fooder/models/meal.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class Diary {
 | 
					class Diary {
 | 
				
			||||||
  final int id;
 | 
					  final int id;
 | 
				
			||||||
  final DateTime date;
 | 
					  final DateTime date;
 | 
				
			||||||
| 
						 | 
					@ -22,13 +21,15 @@ class Diary {
 | 
				
			||||||
    required this.fiber,
 | 
					    required this.fiber,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Diary.fromJson(Map<String, dynamic> map):
 | 
					  Diary.fromJson(Map<String, dynamic> map)
 | 
				
			||||||
    id = map['id'] as int,
 | 
					      : id = map['id'] as int,
 | 
				
			||||||
    date = DateTime.parse(map['date']),
 | 
					        date = DateTime.parse(map['date']),
 | 
				
			||||||
    meals = (map['meals'] as List<dynamic>).map((e) => Meal.fromJson(e as Map<String, dynamic>)).toList(),
 | 
					        meals = (map['meals'] as List<dynamic>)
 | 
				
			||||||
    calories = map['calories'] as double,
 | 
					            .map((e) => Meal.fromJson(e as Map<String, dynamic>))
 | 
				
			||||||
    protein = map['protein'] as double,
 | 
					            .toList(),
 | 
				
			||||||
    carb = map['carb'] as double,
 | 
					        calories = map['calories'] as double,
 | 
				
			||||||
    fat = map['fat'] as double,
 | 
					        protein = map['protein'] as double,
 | 
				
			||||||
    fiber = map['fiber'] as double;
 | 
					        carb = map['carb'] as double,
 | 
				
			||||||
 | 
					        fat = map['fat'] as double,
 | 
				
			||||||
 | 
					        fiber = map['fiber'] as double;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,6 @@ class Entry {
 | 
				
			||||||
  final double fiber;
 | 
					  final double fiber;
 | 
				
			||||||
  final double carb;
 | 
					  final double carb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
  Entry({
 | 
					  Entry({
 | 
				
			||||||
    required this.id,
 | 
					    required this.id,
 | 
				
			||||||
    required this.grams,
 | 
					    required this.grams,
 | 
				
			||||||
| 
						 | 
					@ -24,14 +23,14 @@ class Entry {
 | 
				
			||||||
    required this.carb,
 | 
					    required this.carb,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Entry.fromJson(Map<String, dynamic> map):
 | 
					  Entry.fromJson(Map<String, dynamic> map)
 | 
				
			||||||
    id = map['id'] as int,
 | 
					      : id = map['id'] as int,
 | 
				
			||||||
    grams = map['grams'] as double,
 | 
					        grams = map['grams'] as double,
 | 
				
			||||||
    product = Product.fromJson(map['product'] as Map<String, dynamic>),
 | 
					        product = Product.fromJson(map['product'] as Map<String, dynamic>),
 | 
				
			||||||
    mealId = map['meal_id'] as int,
 | 
					        mealId = map['meal_id'] as int,
 | 
				
			||||||
    calories = map['calories'] as double,
 | 
					        calories = map['calories'] as double,
 | 
				
			||||||
    protein = map['protein'] as double,
 | 
					        protein = map['protein'] as double,
 | 
				
			||||||
    fat = map['fat'] as double,
 | 
					        fat = map['fat'] as double,
 | 
				
			||||||
    fiber = map['fiber'] as double,
 | 
					        fiber = map['fiber'] as double,
 | 
				
			||||||
    carb = map['carb'] as double;
 | 
					        carb = map['carb'] as double;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,5 @@
 | 
				
			||||||
import 'package:fooder/models/entry.dart';
 | 
					import 'package:fooder/models/entry.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class Meal {
 | 
					class Meal {
 | 
				
			||||||
  final List<Entry> entries;
 | 
					  final List<Entry> entries;
 | 
				
			||||||
  final int id;
 | 
					  final int id;
 | 
				
			||||||
| 
						 | 
					@ -26,15 +25,17 @@ class Meal {
 | 
				
			||||||
    required this.diaryId,
 | 
					    required this.diaryId,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Meal.fromJson(Map<String, dynamic> map):
 | 
					  Meal.fromJson(Map<String, dynamic> map)
 | 
				
			||||||
    entries = (map['entries'] as List<dynamic>).map((e) => Entry.fromJson(e as Map<String, dynamic>)).toList(),
 | 
					      : entries = (map['entries'] as List<dynamic>)
 | 
				
			||||||
    id = map['id'] as int,
 | 
					            .map((e) => Entry.fromJson(e as Map<String, dynamic>))
 | 
				
			||||||
    name = map['name'] as String,
 | 
					            .toList(),
 | 
				
			||||||
    order = map['order'] as int,
 | 
					        id = map['id'] as int,
 | 
				
			||||||
    calories = map['calories'] as double,
 | 
					        name = map['name'] as String,
 | 
				
			||||||
    protein = map['protein'] as double,
 | 
					        order = map['order'] as int,
 | 
				
			||||||
    carb = map['carb'] as double,
 | 
					        calories = map['calories'] as double,
 | 
				
			||||||
    fat = map['fat'] as double,
 | 
					        protein = map['protein'] as double,
 | 
				
			||||||
    fiber = map['fiber'] as double,
 | 
					        carb = map['carb'] as double,
 | 
				
			||||||
    diaryId = map['diary_id'] as int;
 | 
					        fat = map['fat'] as double,
 | 
				
			||||||
 | 
					        fiber = map['fiber'] as double,
 | 
				
			||||||
 | 
					        diaryId = map['diary_id'] as int;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,12 +17,12 @@ class Product {
 | 
				
			||||||
    required this.fiber,
 | 
					    required this.fiber,
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Product.fromJson(Map<String, dynamic> map):
 | 
					  Product.fromJson(Map<String, dynamic> map)
 | 
				
			||||||
    id = map['id'] as int,
 | 
					      : id = map['id'] as int,
 | 
				
			||||||
    name = map['name'] as String,
 | 
					        name = map['name'] as String,
 | 
				
			||||||
    calories = map['calories'] as double,
 | 
					        calories = map['calories'] as double,
 | 
				
			||||||
    protein = map['protein'] as double,
 | 
					        protein = map['protein'] as double,
 | 
				
			||||||
    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;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,17 +7,16 @@ import 'package:fooder/models/meal.dart';
 | 
				
			||||||
import 'package:fooder/widgets/product.dart';
 | 
					import 'package:fooder/widgets/product.dart';
 | 
				
			||||||
import 'package:fooder/screens/add_product.dart';
 | 
					import 'package:fooder/screens/add_product.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class AddEntryScreen extends BasedScreen {
 | 
					class AddEntryScreen extends BasedScreen {
 | 
				
			||||||
  final Diary diary;
 | 
					  final Diary diary;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const AddEntryScreen({super.key, required super.apiClient, required this.diary});
 | 
					  const AddEntryScreen(
 | 
				
			||||||
 | 
					      {super.key, required super.apiClient, required this.diary});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  State<AddEntryScreen> createState() => _AddEntryScreen();
 | 
					  State<AddEntryScreen> createState() => _AddEntryScreen();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class _AddEntryScreen extends State<AddEntryScreen> {
 | 
					class _AddEntryScreen extends State<AddEntryScreen> {
 | 
				
			||||||
  final gramsController = TextEditingController();
 | 
					  final gramsController = TextEditingController();
 | 
				
			||||||
  final productNameController = TextEditingController();
 | 
					  final productNameController = TextEditingController();
 | 
				
			||||||
| 
						 | 
					@ -38,7 +37,7 @@ class _AddEntryScreen extends State<AddEntryScreen> {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  void initState () {
 | 
					  void initState() {
 | 
				
			||||||
    super.initState();
 | 
					    super.initState();
 | 
				
			||||||
    setState(() {
 | 
					    setState(() {
 | 
				
			||||||
      meal = widget.diary.meals[0];
 | 
					      meal = widget.diary.meals[0];
 | 
				
			||||||
| 
						 | 
					@ -47,14 +46,16 @@ class _AddEntryScreen extends State<AddEntryScreen> {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<void> _getProducts() async {
 | 
					  Future<void> _getProducts() async {
 | 
				
			||||||
    var productsMap = await widget.apiClient.getProducts(productNameController.text);
 | 
					    var productsMap =
 | 
				
			||||||
 | 
					        await widget.apiClient.getProducts(productNameController.text);
 | 
				
			||||||
    setState(() {
 | 
					    setState(() {
 | 
				
			||||||
      products = (productsMap['products'] as List<dynamic>).map((e) => Product.fromJson(e as Map<String, dynamic>)).toList();
 | 
					      products = (productsMap['products'] as List<dynamic>)
 | 
				
			||||||
 | 
					          .map((e) => Product.fromJson(e as Map<String, dynamic>))
 | 
				
			||||||
 | 
					          .toList();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void showError(String message)
 | 
					  void showError(String message) {
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    ScaffoldMessenger.of(context).showSnackBar(
 | 
					    ScaffoldMessenger.of(context).showSnackBar(
 | 
				
			||||||
      SnackBar(
 | 
					      SnackBar(
 | 
				
			||||||
        content: Text(message, textAlign: TextAlign.center),
 | 
					        content: Text(message, textAlign: TextAlign.center),
 | 
				
			||||||
| 
						 | 
					@ -104,10 +105,9 @@ class _AddEntryScreen extends State<AddEntryScreen> {
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      body: Center(
 | 
					      body: Center(
 | 
				
			||||||
        child: Container(
 | 
					        child: Container(
 | 
				
			||||||
          constraints: const BoxConstraints(maxWidth: 720),
 | 
					            constraints: const BoxConstraints(maxWidth: 720),
 | 
				
			||||||
          padding: const EdgeInsets.all(10),
 | 
					            padding: const EdgeInsets.all(10),
 | 
				
			||||||
          child: ListView(
 | 
					            child: ListView(children: <Widget>[
 | 
				
			||||||
            children: <Widget>[
 | 
					 | 
				
			||||||
              DropdownButton<Meal>(
 | 
					              DropdownButton<Meal>(
 | 
				
			||||||
                value: meal,
 | 
					                value: meal,
 | 
				
			||||||
                // Callback that sets the selected popup menu item.
 | 
					                // Callback that sets the selected popup menu item.
 | 
				
			||||||
| 
						 | 
					@ -131,9 +131,11 @@ class _AddEntryScreen extends State<AddEntryScreen> {
 | 
				
			||||||
                decoration: const InputDecoration(
 | 
					                decoration: const InputDecoration(
 | 
				
			||||||
                  labelText: 'Grams',
 | 
					                  labelText: 'Grams',
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                keyboardType:const TextInputType.numberWithOptions(decimal: true),
 | 
					                keyboardType:
 | 
				
			||||||
 | 
					                    const TextInputType.numberWithOptions(decimal: true),
 | 
				
			||||||
                inputFormatters: <TextInputFormatter>[
 | 
					                inputFormatters: <TextInputFormatter>[
 | 
				
			||||||
                  FilteringTextInputFormatter.allow(RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
					                  FilteringTextInputFormatter.allow(
 | 
				
			||||||
 | 
					                      RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
                controller: gramsController,
 | 
					                controller: gramsController,
 | 
				
			||||||
                onFieldSubmitted: (_) => _addEntry(),
 | 
					                onFieldSubmitted: (_) => _addEntry(),
 | 
				
			||||||
| 
						 | 
					@ -170,20 +172,18 @@ class _AddEntryScreen extends State<AddEntryScreen> {
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
              for (var product in products)
 | 
					              for (var product in products)
 | 
				
			||||||
                ListTile(
 | 
					                ListTile(
 | 
				
			||||||
                onTap: () {
 | 
					                  onTap: () {
 | 
				
			||||||
                  setState(() {
 | 
					                    setState(() {
 | 
				
			||||||
                    products = [product];
 | 
					                      products = [product];
 | 
				
			||||||
                    productNameController.text = product.name;
 | 
					                      productNameController.text = product.name;
 | 
				
			||||||
                    });
 | 
					                    });
 | 
				
			||||||
                  _addEntry(silent: true);
 | 
					                    _addEntry(silent: true);
 | 
				
			||||||
                },
 | 
					                  },
 | 
				
			||||||
                title: ProductWidget(
 | 
					                  title: ProductWidget(
 | 
				
			||||||
                  product: product,
 | 
					                    product: product,
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
              ),
 | 
					            ])),
 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
          )
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      floatingActionButton: FloatingActionButton(
 | 
					      floatingActionButton: FloatingActionButton(
 | 
				
			||||||
        onPressed: _addEntry,
 | 
					        onPressed: _addEntry,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,22 +2,21 @@ import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:fooder/screens/based.dart';
 | 
					import 'package:fooder/screens/based.dart';
 | 
				
			||||||
import 'package:fooder/models/diary.dart';
 | 
					import 'package:fooder/models/diary.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class AddMealScreen extends BasedScreen {
 | 
					class AddMealScreen extends BasedScreen {
 | 
				
			||||||
  final Diary diary;
 | 
					  final Diary diary;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const AddMealScreen({super.key, required super.apiClient, required this.diary});
 | 
					  const AddMealScreen(
 | 
				
			||||||
 | 
					      {super.key, required super.apiClient, required this.diary});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  State<AddMealScreen> createState() => _AddMealScreen();
 | 
					  State<AddMealScreen> createState() => _AddMealScreen();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class _AddMealScreen extends State<AddMealScreen> {
 | 
					class _AddMealScreen extends State<AddMealScreen> {
 | 
				
			||||||
  final nameController = TextEditingController();
 | 
					  final nameController = TextEditingController();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  void initState () {
 | 
					  void initState() {
 | 
				
			||||||
    super.initState();
 | 
					    super.initState();
 | 
				
			||||||
    setState(() {
 | 
					    setState(() {
 | 
				
			||||||
      nameController.text = "Meal ${widget.diary.meals.length}";
 | 
					      nameController.text = "Meal ${widget.diary.meals.length}";
 | 
				
			||||||
| 
						 | 
					@ -36,8 +35,7 @@ class _AddMealScreen extends State<AddMealScreen> {
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void showError(String message)
 | 
					  void showError(String message) {
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    ScaffoldMessenger.of(context).showSnackBar(
 | 
					    ScaffoldMessenger.of(context).showSnackBar(
 | 
				
			||||||
      SnackBar(
 | 
					      SnackBar(
 | 
				
			||||||
        content: Text(message, textAlign: TextAlign.center),
 | 
					        content: Text(message, textAlign: TextAlign.center),
 | 
				
			||||||
| 
						 | 
					@ -63,17 +61,16 @@ class _AddMealScreen extends State<AddMealScreen> {
 | 
				
			||||||
        title: const Text("🅵🅾🅾🅳🅴🆁"),
 | 
					        title: const Text("🅵🅾🅾🅳🅴🆁"),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      body: Center(
 | 
					      body: Center(
 | 
				
			||||||
        child: Container(
 | 
					          child: Container(
 | 
				
			||||||
          constraints: const BoxConstraints(maxWidth: 720),
 | 
					        constraints: const BoxConstraints(maxWidth: 720),
 | 
				
			||||||
          padding: const EdgeInsets.all(10),
 | 
					        padding: const EdgeInsets.all(10),
 | 
				
			||||||
          child: TextFormField(
 | 
					        child: TextFormField(
 | 
				
			||||||
              decoration: const InputDecoration(
 | 
					          decoration: const InputDecoration(
 | 
				
			||||||
                labelText: 'Meal name',
 | 
					            labelText: 'Meal name',
 | 
				
			||||||
              ),
 | 
					          ),
 | 
				
			||||||
              controller: nameController,
 | 
					          controller: nameController,
 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
          )
 | 
					 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
 | 
					      )),
 | 
				
			||||||
      floatingActionButton: FloatingActionButton(
 | 
					      floatingActionButton: FloatingActionButton(
 | 
				
			||||||
        onPressed: _addMeal,
 | 
					        onPressed: _addMeal,
 | 
				
			||||||
        child: const Icon(Icons.add),
 | 
					        child: const Icon(Icons.add),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,6 @@ import 'package:flutter/services.dart';
 | 
				
			||||||
import 'package:fooder/screens/based.dart';
 | 
					import 'package:fooder/screens/based.dart';
 | 
				
			||||||
import 'package:fooder/models/product.dart';
 | 
					import 'package:fooder/models/product.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class AddProductScreen extends BasedScreen {
 | 
					class AddProductScreen extends BasedScreen {
 | 
				
			||||||
  const AddProductScreen({super.key, required super.apiClient});
 | 
					  const AddProductScreen({super.key, required super.apiClient});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,7 +10,6 @@ class AddProductScreen extends BasedScreen {
 | 
				
			||||||
  State<AddProductScreen> createState() => _AddProductScreen();
 | 
					  State<AddProductScreen> createState() => _AddProductScreen();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class _AddProductScreen extends State<AddProductScreen> {
 | 
					class _AddProductScreen extends State<AddProductScreen> {
 | 
				
			||||||
  final nameController = TextEditingController();
 | 
					  final nameController = TextEditingController();
 | 
				
			||||||
  final carbController = TextEditingController();
 | 
					  final carbController = TextEditingController();
 | 
				
			||||||
| 
						 | 
					@ -36,8 +34,7 @@ class _AddProductScreen extends State<AddProductScreen> {
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void showError(String message)
 | 
					  void showError(String message) {
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    ScaffoldMessenger.of(context).showSnackBar(
 | 
					    ScaffoldMessenger.of(context).showSnackBar(
 | 
				
			||||||
      SnackBar(
 | 
					      SnackBar(
 | 
				
			||||||
        content: Text(message, textAlign: TextAlign.center),
 | 
					        content: Text(message, textAlign: TextAlign.center),
 | 
				
			||||||
| 
						 | 
					@ -76,7 +73,8 @@ class _AddProductScreen extends State<AddProductScreen> {
 | 
				
			||||||
      var product = Product.fromJson(productJson);
 | 
					      var product = Product.fromJson(productJson);
 | 
				
			||||||
      popMeDaddy(product);
 | 
					      popMeDaddy(product);
 | 
				
			||||||
    } catch (e) {
 | 
					    } catch (e) {
 | 
				
			||||||
      showError("Error adding product, make sure there is no product with the same name");
 | 
					      showError(
 | 
				
			||||||
 | 
					          "Error adding product, make sure there is no product with the same name");
 | 
				
			||||||
      return;
 | 
					      return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -117,10 +115,9 @@ class _AddProductScreen extends State<AddProductScreen> {
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      body: Center(
 | 
					      body: Center(
 | 
				
			||||||
        child: Container(
 | 
					        child: Container(
 | 
				
			||||||
          constraints: const BoxConstraints(maxWidth: 720),
 | 
					            constraints: const BoxConstraints(maxWidth: 720),
 | 
				
			||||||
          padding: const EdgeInsets.all(10),
 | 
					            padding: const EdgeInsets.all(10),
 | 
				
			||||||
          child: Column(
 | 
					            child: Column(children: <Widget>[
 | 
				
			||||||
            children: <Widget>[
 | 
					 | 
				
			||||||
              TextFormField(
 | 
					              TextFormField(
 | 
				
			||||||
                decoration: const InputDecoration(
 | 
					                decoration: const InputDecoration(
 | 
				
			||||||
                  labelText: 'Product name',
 | 
					                  labelText: 'Product name',
 | 
				
			||||||
| 
						 | 
					@ -131,9 +128,11 @@ class _AddProductScreen extends State<AddProductScreen> {
 | 
				
			||||||
                decoration: const InputDecoration(
 | 
					                decoration: const InputDecoration(
 | 
				
			||||||
                  labelText: 'Carbs',
 | 
					                  labelText: 'Carbs',
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                keyboardType:const TextInputType.numberWithOptions(decimal: true),
 | 
					                keyboardType:
 | 
				
			||||||
 | 
					                    const TextInputType.numberWithOptions(decimal: true),
 | 
				
			||||||
                inputFormatters: <TextInputFormatter>[
 | 
					                inputFormatters: <TextInputFormatter>[
 | 
				
			||||||
                  FilteringTextInputFormatter.allow(RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
					                  FilteringTextInputFormatter.allow(
 | 
				
			||||||
 | 
					                      RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
                controller: carbController,
 | 
					                controller: carbController,
 | 
				
			||||||
                onChanged: (String value) {
 | 
					                onChanged: (String value) {
 | 
				
			||||||
| 
						 | 
					@ -144,9 +143,11 @@ class _AddProductScreen extends State<AddProductScreen> {
 | 
				
			||||||
                decoration: const InputDecoration(
 | 
					                decoration: const InputDecoration(
 | 
				
			||||||
                  labelText: 'Fat',
 | 
					                  labelText: 'Fat',
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                keyboardType:const TextInputType.numberWithOptions(decimal: true),
 | 
					                keyboardType:
 | 
				
			||||||
 | 
					                    const TextInputType.numberWithOptions(decimal: true),
 | 
				
			||||||
                inputFormatters: <TextInputFormatter>[
 | 
					                inputFormatters: <TextInputFormatter>[
 | 
				
			||||||
                  FilteringTextInputFormatter.allow(RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
					                  FilteringTextInputFormatter.allow(
 | 
				
			||||||
 | 
					                      RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
                controller: fatController,
 | 
					                controller: fatController,
 | 
				
			||||||
                onChanged: (String value) {
 | 
					                onChanged: (String value) {
 | 
				
			||||||
| 
						 | 
					@ -157,9 +158,11 @@ class _AddProductScreen extends State<AddProductScreen> {
 | 
				
			||||||
                decoration: const InputDecoration(
 | 
					                decoration: const InputDecoration(
 | 
				
			||||||
                  labelText: 'Protein',
 | 
					                  labelText: 'Protein',
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                keyboardType:const TextInputType.numberWithOptions(decimal: true),
 | 
					                keyboardType:
 | 
				
			||||||
 | 
					                    const TextInputType.numberWithOptions(decimal: true),
 | 
				
			||||||
                inputFormatters: <TextInputFormatter>[
 | 
					                inputFormatters: <TextInputFormatter>[
 | 
				
			||||||
                  FilteringTextInputFormatter.allow(RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
					                  FilteringTextInputFormatter.allow(
 | 
				
			||||||
 | 
					                      RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
                controller: proteinController,
 | 
					                controller: proteinController,
 | 
				
			||||||
                onChanged: (String value) {
 | 
					                onChanged: (String value) {
 | 
				
			||||||
| 
						 | 
					@ -170,9 +173,11 @@ class _AddProductScreen extends State<AddProductScreen> {
 | 
				
			||||||
                decoration: const InputDecoration(
 | 
					                decoration: const InputDecoration(
 | 
				
			||||||
                  labelText: 'Fiber',
 | 
					                  labelText: 'Fiber',
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                keyboardType:const TextInputType.numberWithOptions(decimal: true),
 | 
					                keyboardType:
 | 
				
			||||||
 | 
					                    const TextInputType.numberWithOptions(decimal: true),
 | 
				
			||||||
                inputFormatters: <TextInputFormatter>[
 | 
					                inputFormatters: <TextInputFormatter>[
 | 
				
			||||||
                  FilteringTextInputFormatter.allow(RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
					                  FilteringTextInputFormatter.allow(
 | 
				
			||||||
 | 
					                      RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
                controller: fiberController,
 | 
					                controller: fiberController,
 | 
				
			||||||
                onChanged: (String value) {
 | 
					                onChanged: (String value) {
 | 
				
			||||||
| 
						 | 
					@ -183,9 +188,7 @@ class _AddProductScreen extends State<AddProductScreen> {
 | 
				
			||||||
                "${calculateCalories().toStringAsFixed(2)} kcal",
 | 
					                "${calculateCalories().toStringAsFixed(2)} kcal",
 | 
				
			||||||
                textAlign: TextAlign.right,
 | 
					                textAlign: TextAlign.right,
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
            ]
 | 
					            ])),
 | 
				
			||||||
          )
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      floatingActionButton: FloatingActionButton(
 | 
					      floatingActionButton: FloatingActionButton(
 | 
				
			||||||
        onPressed: _addProduct,
 | 
					        onPressed: _addProduct,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,6 @@
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:fooder/client.dart';
 | 
					import 'package:fooder/client.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
abstract class BasedScreen extends StatefulWidget {
 | 
					abstract class BasedScreen extends StatefulWidget {
 | 
				
			||||||
  final ApiClient apiClient;
 | 
					  final ApiClient apiClient;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,23 +6,21 @@ import 'package:fooder/models/entry.dart';
 | 
				
			||||||
import 'package:fooder/widgets/product.dart';
 | 
					import 'package:fooder/widgets/product.dart';
 | 
				
			||||||
import 'package:fooder/screens/add_product.dart';
 | 
					import 'package:fooder/screens/add_product.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class EditEntryScreen extends BasedScreen {
 | 
					class EditEntryScreen extends BasedScreen {
 | 
				
			||||||
  final Entry entry;
 | 
					  final Entry entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const EditEntryScreen({super.key, required super.apiClient, required this.entry});
 | 
					  const EditEntryScreen(
 | 
				
			||||||
 | 
					      {super.key, required super.apiClient, required this.entry});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  State<EditEntryScreen> createState() => _EditEntryScreen();
 | 
					  State<EditEntryScreen> createState() => _EditEntryScreen();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class _EditEntryScreen extends State<EditEntryScreen> {
 | 
					class _EditEntryScreen extends State<EditEntryScreen> {
 | 
				
			||||||
  final gramsController = TextEditingController();
 | 
					  final gramsController = TextEditingController();
 | 
				
			||||||
  final productNameController = TextEditingController();
 | 
					  final productNameController = TextEditingController();
 | 
				
			||||||
  List<Product> products = [];
 | 
					  List<Product> products = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  void dispose() {
 | 
					  void dispose() {
 | 
				
			||||||
    gramsController.dispose();
 | 
					    gramsController.dispose();
 | 
				
			||||||
| 
						 | 
					@ -35,7 +33,7 @@ class _EditEntryScreen extends State<EditEntryScreen> {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  void initState () {
 | 
					  void initState() {
 | 
				
			||||||
    super.initState();
 | 
					    super.initState();
 | 
				
			||||||
    setState(() {
 | 
					    setState(() {
 | 
				
			||||||
      gramsController.text = widget.entry.grams.toString();
 | 
					      gramsController.text = widget.entry.grams.toString();
 | 
				
			||||||
| 
						 | 
					@ -45,14 +43,16 @@ class _EditEntryScreen extends State<EditEntryScreen> {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<void> _getProducts() async {
 | 
					  Future<void> _getProducts() async {
 | 
				
			||||||
    var productsMap = await widget.apiClient.getProducts(productNameController.text);
 | 
					    var productsMap =
 | 
				
			||||||
 | 
					        await widget.apiClient.getProducts(productNameController.text);
 | 
				
			||||||
    setState(() {
 | 
					    setState(() {
 | 
				
			||||||
      products = (productsMap['products'] as List<dynamic>).map((e) => Product.fromJson(e as Map<String, dynamic>)).toList();
 | 
					      products = (productsMap['products'] as List<dynamic>)
 | 
				
			||||||
 | 
					          .map((e) => Product.fromJson(e as Map<String, dynamic>))
 | 
				
			||||||
 | 
					          .toList();
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void showError(String message)
 | 
					  void showError(String message) {
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    ScaffoldMessenger.of(context).showSnackBar(
 | 
					    ScaffoldMessenger.of(context).showSnackBar(
 | 
				
			||||||
      SnackBar(
 | 
					      SnackBar(
 | 
				
			||||||
        content: Text(message, textAlign: TextAlign.center),
 | 
					        content: Text(message, textAlign: TextAlign.center),
 | 
				
			||||||
| 
						 | 
					@ -104,17 +104,18 @@ class _EditEntryScreen extends State<EditEntryScreen> {
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      body: Center(
 | 
					      body: Center(
 | 
				
			||||||
        child: Container(
 | 
					        child: Container(
 | 
				
			||||||
          constraints: const BoxConstraints(maxWidth: 720),
 | 
					            constraints: const BoxConstraints(maxWidth: 720),
 | 
				
			||||||
          padding: const EdgeInsets.all(10),
 | 
					            padding: const EdgeInsets.all(10),
 | 
				
			||||||
          child: ListView(
 | 
					            child: ListView(children: <Widget>[
 | 
				
			||||||
            children: <Widget>[
 | 
					 | 
				
			||||||
              TextFormField(
 | 
					              TextFormField(
 | 
				
			||||||
                decoration: const InputDecoration(
 | 
					                decoration: const InputDecoration(
 | 
				
			||||||
                  labelText: 'Grams',
 | 
					                  labelText: 'Grams',
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                keyboardType:const TextInputType.numberWithOptions(decimal: true),
 | 
					                keyboardType:
 | 
				
			||||||
 | 
					                    const TextInputType.numberWithOptions(decimal: true),
 | 
				
			||||||
                inputFormatters: <TextInputFormatter>[
 | 
					                inputFormatters: <TextInputFormatter>[
 | 
				
			||||||
                  FilteringTextInputFormatter.allow(RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
					                  FilteringTextInputFormatter.allow(
 | 
				
			||||||
 | 
					                      RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
                controller: gramsController,
 | 
					                controller: gramsController,
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
| 
						 | 
					@ -148,19 +149,17 @@ class _EditEntryScreen extends State<EditEntryScreen> {
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
              for (var product in products)
 | 
					              for (var product in products)
 | 
				
			||||||
                ListTile(
 | 
					                ListTile(
 | 
				
			||||||
                onTap: () {
 | 
					                  onTap: () {
 | 
				
			||||||
                  setState(() {
 | 
					                    setState(() {
 | 
				
			||||||
                    products = [product];
 | 
					                      products = [product];
 | 
				
			||||||
                    productNameController.text = product.name;
 | 
					                      productNameController.text = product.name;
 | 
				
			||||||
                    });
 | 
					                    });
 | 
				
			||||||
                },
 | 
					                  },
 | 
				
			||||||
                title: ProductWidget(
 | 
					                  title: ProductWidget(
 | 
				
			||||||
                  product: product,
 | 
					                    product: product,
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
              ),
 | 
					            ])),
 | 
				
			||||||
            ]
 | 
					 | 
				
			||||||
          )
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      floatingActionButton: Row(
 | 
					      floatingActionButton: Row(
 | 
				
			||||||
        mainAxisAlignment: MainAxisAlignment.end,
 | 
					        mainAxisAlignment: MainAxisAlignment.end,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,6 @@ import 'package:fooder/screens/based.dart';
 | 
				
			||||||
import 'package:fooder/screens/main.dart';
 | 
					import 'package:fooder/screens/main.dart';
 | 
				
			||||||
import 'package:fooder/screens/register.dart';
 | 
					import 'package:fooder/screens/register.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class LoginScreen extends BasedScreen {
 | 
					class LoginScreen extends BasedScreen {
 | 
				
			||||||
  const LoginScreen({super.key, required super.apiClient});
 | 
					  const LoginScreen({super.key, required super.apiClient});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,7 +11,6 @@ class LoginScreen extends BasedScreen {
 | 
				
			||||||
  State<LoginScreen> createState() => _LoginScreen();
 | 
					  State<LoginScreen> createState() => _LoginScreen();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class _LoginScreen extends State<LoginScreen> {
 | 
					class _LoginScreen extends State<LoginScreen> {
 | 
				
			||||||
  final usernameController = TextEditingController();
 | 
					  final usernameController = TextEditingController();
 | 
				
			||||||
  final passwordController = TextEditingController();
 | 
					  final passwordController = TextEditingController();
 | 
				
			||||||
| 
						 | 
					@ -24,8 +22,7 @@ class _LoginScreen extends State<LoginScreen> {
 | 
				
			||||||
    super.dispose();
 | 
					    super.dispose();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void showError(String message)
 | 
					  void showError(String message) {
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    ScaffoldMessenger.of(context).showSnackBar(
 | 
					    ScaffoldMessenger.of(context).showSnackBar(
 | 
				
			||||||
      SnackBar(
 | 
					      SnackBar(
 | 
				
			||||||
        content: Text(message, textAlign: TextAlign.center),
 | 
					        content: Text(message, textAlign: TextAlign.center),
 | 
				
			||||||
| 
						 | 
					@ -34,8 +31,7 @@ class _LoginScreen extends State<LoginScreen> {
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void showText(String text)
 | 
					  void showText(String text) {
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    ScaffoldMessenger.of(context).showSnackBar(
 | 
					    ScaffoldMessenger.of(context).showSnackBar(
 | 
				
			||||||
      SnackBar(
 | 
					      SnackBar(
 | 
				
			||||||
        content: Text(text, textAlign: TextAlign.center),
 | 
					        content: Text(text, textAlign: TextAlign.center),
 | 
				
			||||||
| 
						 | 
					@ -68,9 +64,10 @@ class _LoginScreen extends State<LoginScreen> {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  void initState () {
 | 
					  void initState() {
 | 
				
			||||||
    super.initState();
 | 
					    super.initState();
 | 
				
			||||||
    SystemChannels.textInput.invokeMethod('TextInput.setClientFeatures', <String, dynamic>{
 | 
					    SystemChannels.textInput
 | 
				
			||||||
 | 
					        .invokeMethod('TextInput.setClientFeatures', <String, dynamic>{
 | 
				
			||||||
      'setAuthenticationConfiguration': true,
 | 
					      'setAuthenticationConfiguration': true,
 | 
				
			||||||
      'setAutofillHints': <String>[
 | 
					      'setAutofillHints': <String>[
 | 
				
			||||||
        AutofillHints.username,
 | 
					        AutofillHints.username,
 | 
				
			||||||
| 
						 | 
					@ -140,7 +137,8 @@ class _LoginScreen extends State<LoginScreen> {
 | 
				
			||||||
                      Navigator.push(
 | 
					                      Navigator.push(
 | 
				
			||||||
                        context,
 | 
					                        context,
 | 
				
			||||||
                        MaterialPageRoute(
 | 
					                        MaterialPageRoute(
 | 
				
			||||||
                          builder: (context) => RegisterScreen(apiClient: widget.apiClient),
 | 
					                          builder: (context) =>
 | 
				
			||||||
 | 
					                              RegisterScreen(apiClient: widget.apiClient),
 | 
				
			||||||
                        ),
 | 
					                        ),
 | 
				
			||||||
                      );
 | 
					                      );
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,6 @@ import 'package:fooder/screens/add_entry.dart';
 | 
				
			||||||
import 'package:fooder/models/diary.dart';
 | 
					import 'package:fooder/models/diary.dart';
 | 
				
			||||||
import 'package:fooder/widgets/diary.dart';
 | 
					import 'package:fooder/widgets/diary.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class MainScreen extends BasedScreen {
 | 
					class MainScreen extends BasedScreen {
 | 
				
			||||||
  const MainScreen({super.key, required super.apiClient});
 | 
					  const MainScreen({super.key, required super.apiClient});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,7 +17,7 @@ class _MainScreen extends State<MainScreen> {
 | 
				
			||||||
  DateTime date = DateTime.now();
 | 
					  DateTime date = DateTime.now();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  void initState () {
 | 
					  void initState() {
 | 
				
			||||||
    super.initState();
 | 
					    super.initState();
 | 
				
			||||||
    _asyncInitState().then((value) => null);
 | 
					    _asyncInitState().then((value) => null);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -55,7 +54,8 @@ class _MainScreen extends State<MainScreen> {
 | 
				
			||||||
    await Navigator.push(
 | 
					    await Navigator.push(
 | 
				
			||||||
      context,
 | 
					      context,
 | 
				
			||||||
      MaterialPageRoute(
 | 
					      MaterialPageRoute(
 | 
				
			||||||
        builder: (context) => AddEntryScreen(apiClient: widget.apiClient, diary: diary!),
 | 
					        builder: (context) =>
 | 
				
			||||||
 | 
					            AddEntryScreen(apiClient: widget.apiClient, diary: diary!),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
    ).then((_) => _asyncInitState());
 | 
					    ).then((_) => _asyncInitState());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -69,17 +69,23 @@ class _MainScreen extends State<MainScreen> {
 | 
				
			||||||
      content = Container(
 | 
					      content = Container(
 | 
				
			||||||
        constraints: const BoxConstraints(maxWidth: 720),
 | 
					        constraints: const BoxConstraints(maxWidth: 720),
 | 
				
			||||||
        padding: const EdgeInsets.all(10),
 | 
					        padding: const EdgeInsets.all(10),
 | 
				
			||||||
        child: DiaryWidget(diary: diary!, apiClient: widget.apiClient, refreshParent: _asyncInitState),
 | 
					        child: DiaryWidget(
 | 
				
			||||||
 | 
					            diary: diary!,
 | 
				
			||||||
 | 
					            apiClient: widget.apiClient,
 | 
				
			||||||
 | 
					            refreshParent: _asyncInitState),
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
      title = Row(
 | 
					      title = Row(
 | 
				
			||||||
        mainAxisAlignment: MainAxisAlignment.center,
 | 
					        mainAxisAlignment: MainAxisAlignment.center,
 | 
				
			||||||
        children: <Widget>[
 | 
					        children: <Widget>[
 | 
				
			||||||
          TextButton(
 | 
					          TextButton(
 | 
				
			||||||
            child: const Text("🅵🅾🅾🅳🅴🆁", style: const TextStyle(fontSize: 20, color: Colors.white)),
 | 
					            child: const Text("🅵🅾🅾🅳🅴🆁",
 | 
				
			||||||
 | 
					                style: const TextStyle(fontSize: 20, color: Colors.white)),
 | 
				
			||||||
            onPressed: () {
 | 
					            onPressed: () {
 | 
				
			||||||
              Navigator.pushReplacement(
 | 
					              Navigator.pushReplacement(
 | 
				
			||||||
                context,
 | 
					                context,
 | 
				
			||||||
                MaterialPageRoute(builder: (context) => MainScreen(apiClient: widget.apiClient)),
 | 
					                MaterialPageRoute(
 | 
				
			||||||
 | 
					                    builder: (context) =>
 | 
				
			||||||
 | 
					                        MainScreen(apiClient: widget.apiClient)),
 | 
				
			||||||
              ).then((_) => _asyncInitState());
 | 
					              ).then((_) => _asyncInitState());
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:flutter/services.dart';
 | 
					import 'package:flutter/services.dart';
 | 
				
			||||||
import 'package:fooder/screens/based.dart';
 | 
					import 'package:fooder/screens/based.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class RegisterScreen extends BasedScreen {
 | 
					class RegisterScreen extends BasedScreen {
 | 
				
			||||||
  const RegisterScreen({super.key, required super.apiClient});
 | 
					  const RegisterScreen({super.key, required super.apiClient});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +9,6 @@ class RegisterScreen extends BasedScreen {
 | 
				
			||||||
  State<RegisterScreen> createState() => _RegisterScreen();
 | 
					  State<RegisterScreen> createState() => _RegisterScreen();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class _RegisterScreen extends State<RegisterScreen> {
 | 
					class _RegisterScreen extends State<RegisterScreen> {
 | 
				
			||||||
  final usernameController = TextEditingController();
 | 
					  final usernameController = TextEditingController();
 | 
				
			||||||
  final passwordController = TextEditingController();
 | 
					  final passwordController = TextEditingController();
 | 
				
			||||||
| 
						 | 
					@ -27,7 +25,8 @@ class _RegisterScreen extends State<RegisterScreen> {
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  void initState() {
 | 
					  void initState() {
 | 
				
			||||||
    super.initState();
 | 
					    super.initState();
 | 
				
			||||||
    SystemChannels.textInput.invokeMethod('TextInput.setClientFeatures', <String, dynamic>{
 | 
					    SystemChannels.textInput
 | 
				
			||||||
 | 
					        .invokeMethod('TextInput.setClientFeatures', <String, dynamic>{
 | 
				
			||||||
      'setAuthenticationConfiguration': true,
 | 
					      'setAuthenticationConfiguration': true,
 | 
				
			||||||
      'setAutofillHints': <String>[
 | 
					      'setAutofillHints': <String>[
 | 
				
			||||||
        AutofillHints.username,
 | 
					        AutofillHints.username,
 | 
				
			||||||
| 
						 | 
					@ -36,8 +35,7 @@ class _RegisterScreen extends State<RegisterScreen> {
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void showError(String message)
 | 
					  void showError(String message) {
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    ScaffoldMessenger.of(context).showSnackBar(
 | 
					    ScaffoldMessenger.of(context).showSnackBar(
 | 
				
			||||||
      SnackBar(
 | 
					      SnackBar(
 | 
				
			||||||
        content: Text(message, textAlign: TextAlign.center),
 | 
					        content: Text(message, textAlign: TextAlign.center),
 | 
				
			||||||
| 
						 | 
					@ -46,8 +44,7 @@ class _RegisterScreen extends State<RegisterScreen> {
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void showText(String text)
 | 
					  void showText(String text) {
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    ScaffoldMessenger.of(context).showSnackBar(
 | 
					    ScaffoldMessenger.of(context).showSnackBar(
 | 
				
			||||||
      SnackBar(
 | 
					      SnackBar(
 | 
				
			||||||
        content: Text(text, textAlign: TextAlign.center),
 | 
					        content: Text(text, textAlign: TextAlign.center),
 | 
				
			||||||
| 
						 | 
					@ -110,21 +107,19 @@ class _RegisterScreen extends State<RegisterScreen> {
 | 
				
			||||||
                  autofillHints: const [AutofillHints.password],
 | 
					                  autofillHints: const [AutofillHints.password],
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                TextFormField(
 | 
					                TextFormField(
 | 
				
			||||||
                  obscureText: true,
 | 
					                    obscureText: true,
 | 
				
			||||||
                  decoration: const InputDecoration(
 | 
					                    decoration: const InputDecoration(
 | 
				
			||||||
                    labelText: 'Confirm password',
 | 
					                      labelText: 'Confirm password',
 | 
				
			||||||
                  ),
 | 
					                    ),
 | 
				
			||||||
                  controller: passwordConfirmController,
 | 
					                    controller: passwordConfirmController,
 | 
				
			||||||
                  autofillHints: const [AutofillHints.password],
 | 
					                    autofillHints: const [AutofillHints.password],
 | 
				
			||||||
                  onFieldSubmitted: (_) => _register()
 | 
					                    onFieldSubmitted: (_) => _register()),
 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
                Padding(
 | 
					                Padding(
 | 
				
			||||||
                  padding: const EdgeInsets.symmetric(vertical: 10),
 | 
					                    padding: const EdgeInsets.symmetric(vertical: 10),
 | 
				
			||||||
                  child: FilledButton(
 | 
					                    child: FilledButton(
 | 
				
			||||||
                    onPressed: _register,
 | 
					                      onPressed: _register,
 | 
				
			||||||
                    child: const Text('Register'),
 | 
					                      child: const Text('Register'),
 | 
				
			||||||
                  )
 | 
					                    )),
 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
              ],
 | 
					              ],
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,13 +6,16 @@ import 'package:fooder/client.dart';
 | 
				
			||||||
import 'package:fooder/screens/add_meal.dart';
 | 
					import 'package:fooder/screens/add_meal.dart';
 | 
				
			||||||
import 'dart:core';
 | 
					import 'dart:core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class DiaryWidget extends StatelessWidget {
 | 
					class DiaryWidget extends StatelessWidget {
 | 
				
			||||||
  final Diary diary;
 | 
					  final Diary diary;
 | 
				
			||||||
  final ApiClient apiClient;
 | 
					  final ApiClient apiClient;
 | 
				
			||||||
  final Function() refreshParent;
 | 
					  final Function() refreshParent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const DiaryWidget({super.key, required this.diary, required this.apiClient, required this.refreshParent});
 | 
					  const DiaryWidget(
 | 
				
			||||||
 | 
					      {super.key,
 | 
				
			||||||
 | 
					      required this.diary,
 | 
				
			||||||
 | 
					      required this.apiClient,
 | 
				
			||||||
 | 
					      required this.refreshParent});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
| 
						 | 
					@ -21,34 +24,36 @@ class DiaryWidget extends StatelessWidget {
 | 
				
			||||||
      child: CustomScrollView(
 | 
					      child: CustomScrollView(
 | 
				
			||||||
        slivers: <Widget>[
 | 
					        slivers: <Widget>[
 | 
				
			||||||
          SliverAppBar(
 | 
					          SliverAppBar(
 | 
				
			||||||
            title: Row(
 | 
					              title: Row(
 | 
				
			||||||
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
					                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
				
			||||||
              children: <Widget>[
 | 
					                  children: <Widget>[
 | 
				
			||||||
                const Spacer(),
 | 
					                    const Spacer(),
 | 
				
			||||||
                Text(
 | 
					                    Text(
 | 
				
			||||||
                  "${diary.calories.toStringAsFixed(1)} kcal",
 | 
					                      "${diary.calories.toStringAsFixed(1)} kcal",
 | 
				
			||||||
                  style: Theme.of(context).textTheme.headlineLarge!.copyWith(
 | 
					                      style: Theme.of(context)
 | 
				
			||||||
                    color: Theme.of(context).colorScheme.onSecondary,
 | 
					                          .textTheme
 | 
				
			||||||
                    fontWeight: FontWeight.bold,
 | 
					                          .headlineLarge!
 | 
				
			||||||
                  ),
 | 
					                          .copyWith(
 | 
				
			||||||
                ),
 | 
					                            color: Theme.of(context).colorScheme.onSecondary,
 | 
				
			||||||
              ]
 | 
					                            fontWeight: FontWeight.bold,
 | 
				
			||||||
            ),
 | 
					                          ),
 | 
				
			||||||
            expandedHeight: 150,
 | 
					                    ),
 | 
				
			||||||
            backgroundColor: Theme.of(context).colorScheme.secondary,
 | 
					                  ]),
 | 
				
			||||||
            shape: RoundedRectangleBorder(
 | 
					              expandedHeight: 150,
 | 
				
			||||||
              borderRadius: BorderRadius.circular(8),
 | 
					              backgroundColor: Theme.of(context).colorScheme.secondary,
 | 
				
			||||||
            ),
 | 
					              shape: RoundedRectangleBorder(
 | 
				
			||||||
            floating: true,
 | 
					                borderRadius: BorderRadius.circular(8),
 | 
				
			||||||
            flexibleSpace: FlexibleSpaceBar(
 | 
					              ),
 | 
				
			||||||
              title: MacroWidget(
 | 
					              floating: true,
 | 
				
			||||||
 | 
					              flexibleSpace: FlexibleSpaceBar(
 | 
				
			||||||
 | 
					                title: MacroWidget(
 | 
				
			||||||
                  protein: diary.protein,
 | 
					                  protein: diary.protein,
 | 
				
			||||||
                  carb: diary.carb,
 | 
					                  carb: diary.carb,
 | 
				
			||||||
                  fat: diary.fat,
 | 
					                  fat: diary.fat,
 | 
				
			||||||
                  style: Theme.of(context).textTheme.bodyMedium!.copyWith(
 | 
					                  style: Theme.of(context).textTheme.bodyMedium!.copyWith(
 | 
				
			||||||
                    color: Theme.of(context).colorScheme.onSecondary,
 | 
					                        color: Theme.of(context).colorScheme.onSecondary,
 | 
				
			||||||
                    fontWeight: FontWeight.bold,
 | 
					                        fontWeight: FontWeight.bold,
 | 
				
			||||||
                  ),
 | 
					                      ),
 | 
				
			||||||
                  child: IconButton(
 | 
					                  child: IconButton(
 | 
				
			||||||
                    onPressed: () {
 | 
					                    onPressed: () {
 | 
				
			||||||
                      Navigator.push(
 | 
					                      Navigator.push(
 | 
				
			||||||
| 
						 | 
					@ -63,15 +68,16 @@ class DiaryWidget extends StatelessWidget {
 | 
				
			||||||
                        refreshParent();
 | 
					                        refreshParent();
 | 
				
			||||||
                      });
 | 
					                      });
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                  icon: const Icon(Icons.add),
 | 
					                    icon: const Icon(Icons.add),
 | 
				
			||||||
                  style: ButtonStyle(
 | 
					                    style: ButtonStyle(
 | 
				
			||||||
                    backgroundColor: MaterialStateProperty.all<Color>(Theme.of(context).colorScheme.secondary),
 | 
					                      backgroundColor: MaterialStateProperty.all<Color>(
 | 
				
			||||||
                    foregroundColor: MaterialStateProperty.all<Color>(Theme.of(context).colorScheme.onSecondary),
 | 
					                          Theme.of(context).colorScheme.secondary),
 | 
				
			||||||
                  ),
 | 
					                      foregroundColor: MaterialStateProperty.all<Color>(
 | 
				
			||||||
 | 
					                          Theme.of(context).colorScheme.onSecondary),
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
              )
 | 
					              )),
 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
          SliverList(
 | 
					          SliverList(
 | 
				
			||||||
            delegate: SliverChildListDelegate(
 | 
					            delegate: SliverChildListDelegate(
 | 
				
			||||||
              [
 | 
					              [
 | 
				
			||||||
| 
						 | 
					@ -80,7 +86,7 @@ class DiaryWidget extends StatelessWidget {
 | 
				
			||||||
                    meal: meal,
 | 
					                    meal: meal,
 | 
				
			||||||
                    apiClient: apiClient,
 | 
					                    apiClient: apiClient,
 | 
				
			||||||
                    refreshParent: refreshParent,
 | 
					                    refreshParent: refreshParent,
 | 
				
			||||||
                    ),
 | 
					                  ),
 | 
				
			||||||
              ],
 | 
					              ],
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,6 @@ import 'package:fooder/models/entry.dart';
 | 
				
			||||||
import 'package:fooder/widgets/macro.dart';
 | 
					import 'package:fooder/widgets/macro.dart';
 | 
				
			||||||
import 'dart:core';
 | 
					import 'dart:core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class EntryWidget extends StatelessWidget {
 | 
					class EntryWidget extends StatelessWidget {
 | 
				
			||||||
  final Entry entry;
 | 
					  final Entry entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,8 +31,8 @@ class EntryWidget extends StatelessWidget {
 | 
				
			||||||
            fat: entry.fat,
 | 
					            fat: entry.fat,
 | 
				
			||||||
            amount: entry.grams,
 | 
					            amount: entry.grams,
 | 
				
			||||||
            style: Theme.of(context).textTheme.bodyMedium!.copyWith(
 | 
					            style: Theme.of(context).textTheme.bodyMedium!.copyWith(
 | 
				
			||||||
              color: Theme.of(context).colorScheme.secondary,
 | 
					                  color: Theme.of(context).colorScheme.secondary,
 | 
				
			||||||
            ),
 | 
					                ),
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,5 @@
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class MacroWidget extends StatelessWidget {
 | 
					class MacroWidget extends StatelessWidget {
 | 
				
			||||||
  final double? amount;
 | 
					  final double? amount;
 | 
				
			||||||
  final double? calories;
 | 
					  final double? calories;
 | 
				
			||||||
| 
						 | 
					@ -26,28 +25,28 @@ class MacroWidget extends StatelessWidget {
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    var elements = <Widget>[
 | 
					    var elements = <Widget>[
 | 
				
			||||||
    Expanded(
 | 
					      Expanded(
 | 
				
			||||||
      flex: 1,
 | 
					        flex: 1,
 | 
				
			||||||
      child: Text(
 | 
					        child: Text(
 | 
				
			||||||
        "C: ${carb.toStringAsFixed(1)}g",
 | 
					          "C: ${carb.toStringAsFixed(1)}g",
 | 
				
			||||||
        style: style,
 | 
					          style: style,
 | 
				
			||||||
        textAlign: TextAlign.center,
 | 
					          textAlign: TextAlign.center,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
    Expanded(
 | 
					      Expanded(
 | 
				
			||||||
      flex: 1,
 | 
					        flex: 1,
 | 
				
			||||||
      child: Text(
 | 
					        child: Text(
 | 
				
			||||||
        "F: ${fat.toStringAsFixed(1)}g",
 | 
					          "F: ${fat.toStringAsFixed(1)}g",
 | 
				
			||||||
        style: style,
 | 
					          style: style,
 | 
				
			||||||
        textAlign: TextAlign.center,
 | 
					          textAlign: TextAlign.center,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
    Expanded(
 | 
					      Expanded(
 | 
				
			||||||
      flex: 1,
 | 
					        flex: 1,
 | 
				
			||||||
      child: Text(
 | 
					        child: Text(
 | 
				
			||||||
        "P: ${protein.toStringAsFixed(1)}g",
 | 
					          "P: ${protein.toStringAsFixed(1)}g",
 | 
				
			||||||
        style: style,
 | 
					          style: style,
 | 
				
			||||||
        textAlign: TextAlign.center,
 | 
					          textAlign: TextAlign.center,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
| 
						 | 
					@ -86,7 +85,7 @@ class MacroWidget extends StatelessWidget {
 | 
				
			||||||
            "${amount!.toStringAsFixed(1)}g",
 | 
					            "${amount!.toStringAsFixed(1)}g",
 | 
				
			||||||
            style: style,
 | 
					            style: style,
 | 
				
			||||||
            textAlign: TextAlign.center,
 | 
					            textAlign: TextAlign.center,
 | 
				
			||||||
            ),
 | 
					          ),
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,52 +6,55 @@ import 'package:fooder/screens/edit_entry.dart';
 | 
				
			||||||
import 'package:fooder/client.dart';
 | 
					import 'package:fooder/client.dart';
 | 
				
			||||||
import 'dart:core';
 | 
					import 'dart:core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class MealWidget extends StatelessWidget {
 | 
					class MealWidget extends StatelessWidget {
 | 
				
			||||||
  final Meal meal;
 | 
					  final Meal meal;
 | 
				
			||||||
  final ApiClient apiClient;
 | 
					  final ApiClient apiClient;
 | 
				
			||||||
  final Function() refreshParent;
 | 
					  final Function() refreshParent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const MealWidget({super.key, required this.meal, required this.apiClient, required this.refreshParent});
 | 
					  const MealWidget(
 | 
				
			||||||
 | 
					      {super.key,
 | 
				
			||||||
 | 
					      required this.meal,
 | 
				
			||||||
 | 
					      required this.apiClient,
 | 
				
			||||||
 | 
					      required this.refreshParent});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    return Card(
 | 
					    return Card(
 | 
				
			||||||
      child: Padding(
 | 
					      child: Padding(
 | 
				
			||||||
       padding: const EdgeInsets.only(
 | 
					        padding: const EdgeInsets.only(
 | 
				
			||||||
          top: 36.0, left: 6.0, right: 6.0, bottom: 6.0),
 | 
					            top: 36.0, left: 6.0, right: 6.0, bottom: 6.0),
 | 
				
			||||||
          child: ExpansionTile(
 | 
					        child: ExpansionTile(
 | 
				
			||||||
            title: Column(
 | 
					          title: Column(
 | 
				
			||||||
              children: <Widget>[
 | 
					 | 
				
			||||||
                Row(
 | 
					 | 
				
			||||||
                  children: <Widget>[
 | 
					 | 
				
			||||||
                    Expanded(
 | 
					 | 
				
			||||||
                      child: Text(
 | 
					 | 
				
			||||||
                        meal.name,
 | 
					 | 
				
			||||||
                        style: Theme.of(context).textTheme.titleLarge?.copyWith(
 | 
					 | 
				
			||||||
                          color: Theme.of(context).colorScheme.primary,
 | 
					 | 
				
			||||||
                          ),
 | 
					 | 
				
			||||||
                      ),
 | 
					 | 
				
			||||||
                    ),
 | 
					 | 
				
			||||||
                    Text("${meal.calories.toStringAsFixed(1)} kcal"),
 | 
					 | 
				
			||||||
                  ],
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
                MacroWidget(
 | 
					 | 
				
			||||||
                  protein: meal.protein,
 | 
					 | 
				
			||||||
                  carb: meal.carb,
 | 
					 | 
				
			||||||
                  fat: meal.fat,
 | 
					 | 
				
			||||||
                  style: Theme.of(context).textTheme.bodyMedium!.copyWith(
 | 
					 | 
				
			||||||
                    color: Theme.of(context).colorScheme.secondary,
 | 
					 | 
				
			||||||
                  ),
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
              ],
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
            children: <Widget>[
 | 
					            children: <Widget>[
 | 
				
			||||||
              for (var entry in meal.entries)
 | 
					              Row(
 | 
				
			||||||
                ListTile(
 | 
					                children: <Widget>[
 | 
				
			||||||
                  title: EntryWidget(
 | 
					                  Expanded(
 | 
				
			||||||
                    entry: entry,
 | 
					                    child: Text(
 | 
				
			||||||
 | 
					                      meal.name,
 | 
				
			||||||
 | 
					                      style: Theme.of(context).textTheme.titleLarge?.copyWith(
 | 
				
			||||||
 | 
					                            color: Theme.of(context).colorScheme.primary,
 | 
				
			||||||
 | 
					                          ),
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
 | 
					                  Text("${meal.calories.toStringAsFixed(1)} kcal"),
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					              MacroWidget(
 | 
				
			||||||
 | 
					                protein: meal.protein,
 | 
				
			||||||
 | 
					                carb: meal.carb,
 | 
				
			||||||
 | 
					                fat: meal.fat,
 | 
				
			||||||
 | 
					                style: Theme.of(context).textTheme.bodyMedium!.copyWith(
 | 
				
			||||||
 | 
					                      color: Theme.of(context).colorScheme.secondary,
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					          children: <Widget>[
 | 
				
			||||||
 | 
					            for (var entry in meal.entries)
 | 
				
			||||||
 | 
					              ListTile(
 | 
				
			||||||
 | 
					                title: EntryWidget(
 | 
				
			||||||
 | 
					                  entry: entry,
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
                onTap: () {
 | 
					                onTap: () {
 | 
				
			||||||
                  Navigator.push(
 | 
					                  Navigator.push(
 | 
				
			||||||
                    context,
 | 
					                    context,
 | 
				
			||||||
| 
						 | 
					@ -65,7 +68,7 @@ class MealWidget extends StatelessWidget {
 | 
				
			||||||
                    refreshParent();
 | 
					                    refreshParent();
 | 
				
			||||||
                  });
 | 
					                  });
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
                )
 | 
					              )
 | 
				
			||||||
          ],
 | 
					          ],
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,6 @@ import 'package:fooder/models/product.dart';
 | 
				
			||||||
import 'package:fooder/widgets/macro.dart';
 | 
					import 'package:fooder/widgets/macro.dart';
 | 
				
			||||||
import 'dart:core';
 | 
					import 'dart:core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class ProductWidget extends StatelessWidget {
 | 
					class ProductWidget extends StatelessWidget {
 | 
				
			||||||
  final Product product;
 | 
					  final Product product;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,9 +31,9 @@ class ProductWidget extends StatelessWidget {
 | 
				
			||||||
            fat: product.fat,
 | 
					            fat: product.fat,
 | 
				
			||||||
            fiber: product.fiber,
 | 
					            fiber: product.fiber,
 | 
				
			||||||
            style: Theme.of(context).textTheme.bodyMedium!.copyWith(
 | 
					            style: Theme.of(context).textTheme.bodyMedium!.copyWith(
 | 
				
			||||||
              color: Theme.of(context).colorScheme.secondary,
 | 
					                  color: Theme.of(context).colorScheme.secondary,
 | 
				
			||||||
              fontWeight: FontWeight.bold,
 | 
					                  fontWeight: FontWeight.bold,
 | 
				
			||||||
            ),
 | 
					                ),
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue