[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 'package:intl/intl.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ApiClient {
 | 
			
		||||
  final String baseUrl;
 | 
			
		||||
  String? token;
 | 
			
		||||
| 
						 | 
				
			
			@ -67,7 +66,8 @@ class ApiClient {
 | 
			
		|||
    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(
 | 
			
		||||
      Uri.parse('$baseUrl$path'),
 | 
			
		||||
      body: jsonEncode(body),
 | 
			
		||||
| 
						 | 
				
			
			@ -86,7 +86,6 @@ class ApiClient {
 | 
			
		|||
    return _jsonDecode(response);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Future<void> delete(String path) async {
 | 
			
		||||
    final response = await httpClient.delete(
 | 
			
		||||
      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(
 | 
			
		||||
      Uri.parse('$baseUrl$path'),
 | 
			
		||||
      body: jsonEncode(body),
 | 
			
		||||
| 
						 | 
				
			
			@ -155,12 +155,9 @@ class ApiClient {
 | 
			
		|||
      throw Exception("No valid refresh token found");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    final response = await post(
 | 
			
		||||
      "/token/refresh",
 | 
			
		||||
      {
 | 
			
		||||
    final response = await post("/token/refresh", {
 | 
			
		||||
      "refresh_token": refreshToken,
 | 
			
		||||
      }
 | 
			
		||||
    );
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    token = response['access_token'] as String;
 | 
			
		||||
    window.localStorage['token'] = token!;
 | 
			
		||||
| 
						 | 
				
			
			@ -185,7 +182,8 @@ class ApiClient {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -193,8 +191,7 @@ class ApiClient {
 | 
			
		|||
    required double grams,
 | 
			
		||||
    required int productId,
 | 
			
		||||
    required int mealId,
 | 
			
		||||
  }
 | 
			
		||||
  ) async {
 | 
			
		||||
  }) async {
 | 
			
		||||
    var entry = {
 | 
			
		||||
      "grams": grams,
 | 
			
		||||
      "product_id": productId,
 | 
			
		||||
| 
						 | 
				
			
			@ -207,12 +204,12 @@ class ApiClient {
 | 
			
		|||
    await delete("/entry/$id");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<void> updateEntry(int id, {
 | 
			
		||||
  Future<void> updateEntry(
 | 
			
		||||
    int id, {
 | 
			
		||||
    required double grams,
 | 
			
		||||
    required int productId,
 | 
			
		||||
    required int mealId,
 | 
			
		||||
  }
 | 
			
		||||
  ) async {
 | 
			
		||||
  }) async {
 | 
			
		||||
    var entry = {
 | 
			
		||||
      "grams": grams,
 | 
			
		||||
      "product_id": productId,
 | 
			
		||||
| 
						 | 
				
			
			@ -223,7 +220,9 @@ class ApiClient {
 | 
			
		|||
 | 
			
		||||
  Future<void> register(String username, String password) async {
 | 
			
		||||
    try {
 | 
			
		||||
      await post("/user", {
 | 
			
		||||
      await post(
 | 
			
		||||
        "/user",
 | 
			
		||||
        {
 | 
			
		||||
          "username": username,
 | 
			
		||||
          "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", {
 | 
			
		||||
      "name": name,
 | 
			
		||||
      "diary_id": diaryId,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
 | 
			
		|||
import 'package:fooder/screens/login.dart';
 | 
			
		||||
import 'package:fooder/client.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MyApp extends StatelessWidget {
 | 
			
		||||
  const MyApp({super.key});
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -26,7 +25,6 @@ class MyApp extends StatelessWidget {
 | 
			
		|||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void main() {
 | 
			
		||||
  runApp(const MyApp());
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,5 @@
 | 
			
		|||
import 'package:fooder/models/meal.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Diary {
 | 
			
		||||
  final int id;
 | 
			
		||||
  final DateTime date;
 | 
			
		||||
| 
						 | 
				
			
			@ -22,10 +21,12 @@ class Diary {
 | 
			
		|||
    required this.fiber,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  Diary.fromJson(Map<String, dynamic> map):
 | 
			
		||||
    id = map['id'] as int,
 | 
			
		||||
  Diary.fromJson(Map<String, dynamic> map)
 | 
			
		||||
      : id = map['id'] as int,
 | 
			
		||||
        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>)
 | 
			
		||||
            .map((e) => Meal.fromJson(e as Map<String, dynamic>))
 | 
			
		||||
            .toList(),
 | 
			
		||||
        calories = map['calories'] as double,
 | 
			
		||||
        protein = map['protein'] as double,
 | 
			
		||||
        carb = map['carb'] as double,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,6 @@ class Entry {
 | 
			
		|||
  final double fiber;
 | 
			
		||||
  final double carb;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  Entry({
 | 
			
		||||
    required this.id,
 | 
			
		||||
    required this.grams,
 | 
			
		||||
| 
						 | 
				
			
			@ -24,8 +23,8 @@ class Entry {
 | 
			
		|||
    required this.carb,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  Entry.fromJson(Map<String, dynamic> map):
 | 
			
		||||
    id = map['id'] as int,
 | 
			
		||||
  Entry.fromJson(Map<String, dynamic> map)
 | 
			
		||||
      : id = map['id'] as int,
 | 
			
		||||
        grams = map['grams'] as double,
 | 
			
		||||
        product = Product.fromJson(map['product'] as Map<String, dynamic>),
 | 
			
		||||
        mealId = map['meal_id'] as int,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,5 @@
 | 
			
		|||
import 'package:fooder/models/entry.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Meal {
 | 
			
		||||
  final List<Entry> entries;
 | 
			
		||||
  final int id;
 | 
			
		||||
| 
						 | 
				
			
			@ -26,8 +25,10 @@ class Meal {
 | 
			
		|||
    required this.diaryId,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  Meal.fromJson(Map<String, dynamic> map):
 | 
			
		||||
    entries = (map['entries'] as List<dynamic>).map((e) => Entry.fromJson(e as Map<String, dynamic>)).toList(),
 | 
			
		||||
  Meal.fromJson(Map<String, dynamic> map)
 | 
			
		||||
      : entries = (map['entries'] as List<dynamic>)
 | 
			
		||||
            .map((e) => Entry.fromJson(e as Map<String, dynamic>))
 | 
			
		||||
            .toList(),
 | 
			
		||||
        id = map['id'] as int,
 | 
			
		||||
        name = map['name'] as String,
 | 
			
		||||
        order = map['order'] as int,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,8 +17,8 @@ class Product {
 | 
			
		|||
    required this.fiber,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  Product.fromJson(Map<String, dynamic> map):
 | 
			
		||||
    id = map['id'] as int,
 | 
			
		||||
  Product.fromJson(Map<String, dynamic> map)
 | 
			
		||||
      : id = map['id'] as int,
 | 
			
		||||
        name = map['name'] as String,
 | 
			
		||||
        calories = map['calories'] as double,
 | 
			
		||||
        protein = map['protein'] as double,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,17 +7,16 @@ import 'package:fooder/models/meal.dart';
 | 
			
		|||
import 'package:fooder/widgets/product.dart';
 | 
			
		||||
import 'package:fooder/screens/add_product.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AddEntryScreen extends BasedScreen {
 | 
			
		||||
  final Diary diary;
 | 
			
		||||
 | 
			
		||||
  const AddEntryScreen({super.key, required super.apiClient, required this.diary});
 | 
			
		||||
  const AddEntryScreen(
 | 
			
		||||
      {super.key, required super.apiClient, required this.diary});
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  State<AddEntryScreen> createState() => _AddEntryScreen();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class _AddEntryScreen extends State<AddEntryScreen> {
 | 
			
		||||
  final gramsController = TextEditingController();
 | 
			
		||||
  final productNameController = TextEditingController();
 | 
			
		||||
| 
						 | 
				
			
			@ -47,14 +46,16 @@ class _AddEntryScreen extends State<AddEntryScreen> {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  Future<void> _getProducts() async {
 | 
			
		||||
    var productsMap = await widget.apiClient.getProducts(productNameController.text);
 | 
			
		||||
    var productsMap =
 | 
			
		||||
        await widget.apiClient.getProducts(productNameController.text);
 | 
			
		||||
    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(
 | 
			
		||||
      SnackBar(
 | 
			
		||||
        content: Text(message, textAlign: TextAlign.center),
 | 
			
		||||
| 
						 | 
				
			
			@ -106,8 +107,7 @@ class _AddEntryScreen extends State<AddEntryScreen> {
 | 
			
		|||
        child: Container(
 | 
			
		||||
            constraints: const BoxConstraints(maxWidth: 720),
 | 
			
		||||
            padding: const EdgeInsets.all(10),
 | 
			
		||||
          child: ListView(
 | 
			
		||||
            children: <Widget>[
 | 
			
		||||
            child: ListView(children: <Widget>[
 | 
			
		||||
              DropdownButton<Meal>(
 | 
			
		||||
                value: meal,
 | 
			
		||||
                // Callback that sets the selected popup menu item.
 | 
			
		||||
| 
						 | 
				
			
			@ -131,9 +131,11 @@ class _AddEntryScreen extends State<AddEntryScreen> {
 | 
			
		|||
                decoration: const InputDecoration(
 | 
			
		||||
                  labelText: 'Grams',
 | 
			
		||||
                ),
 | 
			
		||||
                keyboardType:const TextInputType.numberWithOptions(decimal: true),
 | 
			
		||||
                keyboardType:
 | 
			
		||||
                    const TextInputType.numberWithOptions(decimal: true),
 | 
			
		||||
                inputFormatters: <TextInputFormatter>[
 | 
			
		||||
                  FilteringTextInputFormatter.allow(RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
			
		||||
                  FilteringTextInputFormatter.allow(
 | 
			
		||||
                      RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
			
		||||
                ],
 | 
			
		||||
                controller: gramsController,
 | 
			
		||||
                onFieldSubmitted: (_) => _addEntry(),
 | 
			
		||||
| 
						 | 
				
			
			@ -181,9 +183,7 @@ class _AddEntryScreen extends State<AddEntryScreen> {
 | 
			
		|||
                    product: product,
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
            ]
 | 
			
		||||
          )
 | 
			
		||||
        ),
 | 
			
		||||
            ])),
 | 
			
		||||
      ),
 | 
			
		||||
      floatingActionButton: FloatingActionButton(
 | 
			
		||||
        onPressed: _addEntry,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,17 +2,16 @@ import 'package:flutter/material.dart';
 | 
			
		|||
import 'package:fooder/screens/based.dart';
 | 
			
		||||
import 'package:fooder/models/diary.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AddMealScreen extends BasedScreen {
 | 
			
		||||
  final Diary diary;
 | 
			
		||||
 | 
			
		||||
  const AddMealScreen({super.key, required super.apiClient, required this.diary});
 | 
			
		||||
  const AddMealScreen(
 | 
			
		||||
      {super.key, required super.apiClient, required this.diary});
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  State<AddMealScreen> createState() => _AddMealScreen();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class _AddMealScreen extends State<AddMealScreen> {
 | 
			
		||||
  final nameController = TextEditingController();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -36,8 +35,7 @@ class _AddMealScreen extends State<AddMealScreen> {
 | 
			
		|||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void showError(String message)
 | 
			
		||||
  {
 | 
			
		||||
  void showError(String message) {
 | 
			
		||||
    ScaffoldMessenger.of(context).showSnackBar(
 | 
			
		||||
      SnackBar(
 | 
			
		||||
        content: Text(message, textAlign: TextAlign.center),
 | 
			
		||||
| 
						 | 
				
			
			@ -72,8 +70,7 @@ class _AddMealScreen extends State<AddMealScreen> {
 | 
			
		|||
          ),
 | 
			
		||||
          controller: nameController,
 | 
			
		||||
        ),
 | 
			
		||||
          )
 | 
			
		||||
        ),
 | 
			
		||||
      )),
 | 
			
		||||
      floatingActionButton: FloatingActionButton(
 | 
			
		||||
        onPressed: _addMeal,
 | 
			
		||||
        child: const Icon(Icons.add),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,6 @@ import 'package:flutter/services.dart';
 | 
			
		|||
import 'package:fooder/screens/based.dart';
 | 
			
		||||
import 'package:fooder/models/product.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AddProductScreen extends BasedScreen {
 | 
			
		||||
  const AddProductScreen({super.key, required super.apiClient});
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -11,7 +10,6 @@ class AddProductScreen extends BasedScreen {
 | 
			
		|||
  State<AddProductScreen> createState() => _AddProductScreen();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class _AddProductScreen extends State<AddProductScreen> {
 | 
			
		||||
  final nameController = 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(
 | 
			
		||||
      SnackBar(
 | 
			
		||||
        content: Text(message, textAlign: TextAlign.center),
 | 
			
		||||
| 
						 | 
				
			
			@ -76,7 +73,8 @@ class _AddProductScreen extends State<AddProductScreen> {
 | 
			
		|||
      var product = Product.fromJson(productJson);
 | 
			
		||||
      popMeDaddy(product);
 | 
			
		||||
    } 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;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -119,8 +117,7 @@ class _AddProductScreen extends State<AddProductScreen> {
 | 
			
		|||
        child: Container(
 | 
			
		||||
            constraints: const BoxConstraints(maxWidth: 720),
 | 
			
		||||
            padding: const EdgeInsets.all(10),
 | 
			
		||||
          child: Column(
 | 
			
		||||
            children: <Widget>[
 | 
			
		||||
            child: Column(children: <Widget>[
 | 
			
		||||
              TextFormField(
 | 
			
		||||
                decoration: const InputDecoration(
 | 
			
		||||
                  labelText: 'Product name',
 | 
			
		||||
| 
						 | 
				
			
			@ -131,9 +128,11 @@ class _AddProductScreen extends State<AddProductScreen> {
 | 
			
		|||
                decoration: const InputDecoration(
 | 
			
		||||
                  labelText: 'Carbs',
 | 
			
		||||
                ),
 | 
			
		||||
                keyboardType:const TextInputType.numberWithOptions(decimal: true),
 | 
			
		||||
                keyboardType:
 | 
			
		||||
                    const TextInputType.numberWithOptions(decimal: true),
 | 
			
		||||
                inputFormatters: <TextInputFormatter>[
 | 
			
		||||
                  FilteringTextInputFormatter.allow(RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
			
		||||
                  FilteringTextInputFormatter.allow(
 | 
			
		||||
                      RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
			
		||||
                ],
 | 
			
		||||
                controller: carbController,
 | 
			
		||||
                onChanged: (String value) {
 | 
			
		||||
| 
						 | 
				
			
			@ -144,9 +143,11 @@ class _AddProductScreen extends State<AddProductScreen> {
 | 
			
		|||
                decoration: const InputDecoration(
 | 
			
		||||
                  labelText: 'Fat',
 | 
			
		||||
                ),
 | 
			
		||||
                keyboardType:const TextInputType.numberWithOptions(decimal: true),
 | 
			
		||||
                keyboardType:
 | 
			
		||||
                    const TextInputType.numberWithOptions(decimal: true),
 | 
			
		||||
                inputFormatters: <TextInputFormatter>[
 | 
			
		||||
                  FilteringTextInputFormatter.allow(RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
			
		||||
                  FilteringTextInputFormatter.allow(
 | 
			
		||||
                      RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
			
		||||
                ],
 | 
			
		||||
                controller: fatController,
 | 
			
		||||
                onChanged: (String value) {
 | 
			
		||||
| 
						 | 
				
			
			@ -157,9 +158,11 @@ class _AddProductScreen extends State<AddProductScreen> {
 | 
			
		|||
                decoration: const InputDecoration(
 | 
			
		||||
                  labelText: 'Protein',
 | 
			
		||||
                ),
 | 
			
		||||
                keyboardType:const TextInputType.numberWithOptions(decimal: true),
 | 
			
		||||
                keyboardType:
 | 
			
		||||
                    const TextInputType.numberWithOptions(decimal: true),
 | 
			
		||||
                inputFormatters: <TextInputFormatter>[
 | 
			
		||||
                  FilteringTextInputFormatter.allow(RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
			
		||||
                  FilteringTextInputFormatter.allow(
 | 
			
		||||
                      RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
			
		||||
                ],
 | 
			
		||||
                controller: proteinController,
 | 
			
		||||
                onChanged: (String value) {
 | 
			
		||||
| 
						 | 
				
			
			@ -170,9 +173,11 @@ class _AddProductScreen extends State<AddProductScreen> {
 | 
			
		|||
                decoration: const InputDecoration(
 | 
			
		||||
                  labelText: 'Fiber',
 | 
			
		||||
                ),
 | 
			
		||||
                keyboardType:const TextInputType.numberWithOptions(decimal: true),
 | 
			
		||||
                keyboardType:
 | 
			
		||||
                    const TextInputType.numberWithOptions(decimal: true),
 | 
			
		||||
                inputFormatters: <TextInputFormatter>[
 | 
			
		||||
                  FilteringTextInputFormatter.allow(RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
			
		||||
                  FilteringTextInputFormatter.allow(
 | 
			
		||||
                      RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
			
		||||
                ],
 | 
			
		||||
                controller: fiberController,
 | 
			
		||||
                onChanged: (String value) {
 | 
			
		||||
| 
						 | 
				
			
			@ -183,9 +188,7 @@ class _AddProductScreen extends State<AddProductScreen> {
 | 
			
		|||
                "${calculateCalories().toStringAsFixed(2)} kcal",
 | 
			
		||||
                textAlign: TextAlign.right,
 | 
			
		||||
              ),
 | 
			
		||||
            ]
 | 
			
		||||
          )
 | 
			
		||||
        ),
 | 
			
		||||
            ])),
 | 
			
		||||
      ),
 | 
			
		||||
      floatingActionButton: FloatingActionButton(
 | 
			
		||||
        onPressed: _addProduct,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,6 @@
 | 
			
		|||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:fooder/client.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
abstract class BasedScreen extends StatefulWidget {
 | 
			
		||||
  final ApiClient apiClient;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,23 +6,21 @@ import 'package:fooder/models/entry.dart';
 | 
			
		|||
import 'package:fooder/widgets/product.dart';
 | 
			
		||||
import 'package:fooder/screens/add_product.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EditEntryScreen extends BasedScreen {
 | 
			
		||||
  final Entry entry;
 | 
			
		||||
 | 
			
		||||
  const EditEntryScreen({super.key, required super.apiClient, required this.entry});
 | 
			
		||||
  const EditEntryScreen(
 | 
			
		||||
      {super.key, required super.apiClient, required this.entry});
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  State<EditEntryScreen> createState() => _EditEntryScreen();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class _EditEntryScreen extends State<EditEntryScreen> {
 | 
			
		||||
  final gramsController = TextEditingController();
 | 
			
		||||
  final productNameController = TextEditingController();
 | 
			
		||||
  List<Product> products = [];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void dispose() {
 | 
			
		||||
    gramsController.dispose();
 | 
			
		||||
| 
						 | 
				
			
			@ -45,14 +43,16 @@ class _EditEntryScreen extends State<EditEntryScreen> {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  Future<void> _getProducts() async {
 | 
			
		||||
    var productsMap = await widget.apiClient.getProducts(productNameController.text);
 | 
			
		||||
    var productsMap =
 | 
			
		||||
        await widget.apiClient.getProducts(productNameController.text);
 | 
			
		||||
    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(
 | 
			
		||||
      SnackBar(
 | 
			
		||||
        content: Text(message, textAlign: TextAlign.center),
 | 
			
		||||
| 
						 | 
				
			
			@ -106,15 +106,16 @@ class _EditEntryScreen extends State<EditEntryScreen> {
 | 
			
		|||
        child: Container(
 | 
			
		||||
            constraints: const BoxConstraints(maxWidth: 720),
 | 
			
		||||
            padding: const EdgeInsets.all(10),
 | 
			
		||||
          child: ListView(
 | 
			
		||||
            children: <Widget>[
 | 
			
		||||
            child: ListView(children: <Widget>[
 | 
			
		||||
              TextFormField(
 | 
			
		||||
                decoration: const InputDecoration(
 | 
			
		||||
                  labelText: 'Grams',
 | 
			
		||||
                ),
 | 
			
		||||
                keyboardType:const TextInputType.numberWithOptions(decimal: true),
 | 
			
		||||
                keyboardType:
 | 
			
		||||
                    const TextInputType.numberWithOptions(decimal: true),
 | 
			
		||||
                inputFormatters: <TextInputFormatter>[
 | 
			
		||||
                  FilteringTextInputFormatter.allow(RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
			
		||||
                  FilteringTextInputFormatter.allow(
 | 
			
		||||
                      RegExp(r'^(\d+)?[\.,]?\d{0,2}')),
 | 
			
		||||
                ],
 | 
			
		||||
                controller: gramsController,
 | 
			
		||||
              ),
 | 
			
		||||
| 
						 | 
				
			
			@ -158,9 +159,7 @@ class _EditEntryScreen extends State<EditEntryScreen> {
 | 
			
		|||
                    product: product,
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
            ]
 | 
			
		||||
          )
 | 
			
		||||
        ),
 | 
			
		||||
            ])),
 | 
			
		||||
      ),
 | 
			
		||||
      floatingActionButton: Row(
 | 
			
		||||
        mainAxisAlignment: MainAxisAlignment.end,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,6 @@ import 'package:fooder/screens/based.dart';
 | 
			
		|||
import 'package:fooder/screens/main.dart';
 | 
			
		||||
import 'package:fooder/screens/register.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LoginScreen extends BasedScreen {
 | 
			
		||||
  const LoginScreen({super.key, required super.apiClient});
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -12,7 +11,6 @@ class LoginScreen extends BasedScreen {
 | 
			
		|||
  State<LoginScreen> createState() => _LoginScreen();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class _LoginScreen extends State<LoginScreen> {
 | 
			
		||||
  final usernameController = TextEditingController();
 | 
			
		||||
  final passwordController = TextEditingController();
 | 
			
		||||
| 
						 | 
				
			
			@ -24,8 +22,7 @@ class _LoginScreen extends State<LoginScreen> {
 | 
			
		|||
    super.dispose();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void showError(String message)
 | 
			
		||||
  {
 | 
			
		||||
  void showError(String message) {
 | 
			
		||||
    ScaffoldMessenger.of(context).showSnackBar(
 | 
			
		||||
      SnackBar(
 | 
			
		||||
        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(
 | 
			
		||||
      SnackBar(
 | 
			
		||||
        content: Text(text, textAlign: TextAlign.center),
 | 
			
		||||
| 
						 | 
				
			
			@ -70,7 +66,8 @@ class _LoginScreen extends State<LoginScreen> {
 | 
			
		|||
  @override
 | 
			
		||||
  void initState() {
 | 
			
		||||
    super.initState();
 | 
			
		||||
    SystemChannels.textInput.invokeMethod('TextInput.setClientFeatures', <String, dynamic>{
 | 
			
		||||
    SystemChannels.textInput
 | 
			
		||||
        .invokeMethod('TextInput.setClientFeatures', <String, dynamic>{
 | 
			
		||||
      'setAuthenticationConfiguration': true,
 | 
			
		||||
      'setAutofillHints': <String>[
 | 
			
		||||
        AutofillHints.username,
 | 
			
		||||
| 
						 | 
				
			
			@ -140,7 +137,8 @@ class _LoginScreen extends State<LoginScreen> {
 | 
			
		|||
                      Navigator.push(
 | 
			
		||||
                        context,
 | 
			
		||||
                        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/widgets/diary.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MainScreen extends BasedScreen {
 | 
			
		||||
  const MainScreen({super.key, required super.apiClient});
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -55,7 +54,8 @@ class _MainScreen extends State<MainScreen> {
 | 
			
		|||
    await Navigator.push(
 | 
			
		||||
      context,
 | 
			
		||||
      MaterialPageRoute(
 | 
			
		||||
        builder: (context) => AddEntryScreen(apiClient: widget.apiClient, diary: diary!),
 | 
			
		||||
        builder: (context) =>
 | 
			
		||||
            AddEntryScreen(apiClient: widget.apiClient, diary: diary!),
 | 
			
		||||
      ),
 | 
			
		||||
    ).then((_) => _asyncInitState());
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -69,17 +69,23 @@ class _MainScreen extends State<MainScreen> {
 | 
			
		|||
      content = Container(
 | 
			
		||||
        constraints: const BoxConstraints(maxWidth: 720),
 | 
			
		||||
        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(
 | 
			
		||||
        mainAxisAlignment: MainAxisAlignment.center,
 | 
			
		||||
        children: <Widget>[
 | 
			
		||||
          TextButton(
 | 
			
		||||
            child: const Text("🅵🅾🅾🅳🅴🆁", style: const TextStyle(fontSize: 20, color: Colors.white)),
 | 
			
		||||
            child: const Text("🅵🅾🅾🅳🅴🆁",
 | 
			
		||||
                style: const TextStyle(fontSize: 20, color: Colors.white)),
 | 
			
		||||
            onPressed: () {
 | 
			
		||||
              Navigator.pushReplacement(
 | 
			
		||||
                context,
 | 
			
		||||
                MaterialPageRoute(builder: (context) => MainScreen(apiClient: widget.apiClient)),
 | 
			
		||||
                MaterialPageRoute(
 | 
			
		||||
                    builder: (context) =>
 | 
			
		||||
                        MainScreen(apiClient: widget.apiClient)),
 | 
			
		||||
              ).then((_) => _asyncInitState());
 | 
			
		||||
            },
 | 
			
		||||
          ),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
 | 
			
		|||
import 'package:flutter/services.dart';
 | 
			
		||||
import 'package:fooder/screens/based.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RegisterScreen extends BasedScreen {
 | 
			
		||||
  const RegisterScreen({super.key, required super.apiClient});
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -10,7 +9,6 @@ class RegisterScreen extends BasedScreen {
 | 
			
		|||
  State<RegisterScreen> createState() => _RegisterScreen();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class _RegisterScreen extends State<RegisterScreen> {
 | 
			
		||||
  final usernameController = TextEditingController();
 | 
			
		||||
  final passwordController = TextEditingController();
 | 
			
		||||
| 
						 | 
				
			
			@ -27,7 +25,8 @@ class _RegisterScreen extends State<RegisterScreen> {
 | 
			
		|||
  @override
 | 
			
		||||
  void initState() {
 | 
			
		||||
    super.initState();
 | 
			
		||||
    SystemChannels.textInput.invokeMethod('TextInput.setClientFeatures', <String, dynamic>{
 | 
			
		||||
    SystemChannels.textInput
 | 
			
		||||
        .invokeMethod('TextInput.setClientFeatures', <String, dynamic>{
 | 
			
		||||
      'setAuthenticationConfiguration': true,
 | 
			
		||||
      'setAutofillHints': <String>[
 | 
			
		||||
        AutofillHints.username,
 | 
			
		||||
| 
						 | 
				
			
			@ -36,8 +35,7 @@ class _RegisterScreen extends State<RegisterScreen> {
 | 
			
		|||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void showError(String message)
 | 
			
		||||
  {
 | 
			
		||||
  void showError(String message) {
 | 
			
		||||
    ScaffoldMessenger.of(context).showSnackBar(
 | 
			
		||||
      SnackBar(
 | 
			
		||||
        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(
 | 
			
		||||
      SnackBar(
 | 
			
		||||
        content: Text(text, textAlign: TextAlign.center),
 | 
			
		||||
| 
						 | 
				
			
			@ -116,15 +113,13 @@ class _RegisterScreen extends State<RegisterScreen> {
 | 
			
		|||
                    ),
 | 
			
		||||
                    controller: passwordConfirmController,
 | 
			
		||||
                    autofillHints: const [AutofillHints.password],
 | 
			
		||||
                  onFieldSubmitted: (_) => _register()
 | 
			
		||||
                ),
 | 
			
		||||
                    onFieldSubmitted: (_) => _register()),
 | 
			
		||||
                Padding(
 | 
			
		||||
                    padding: const EdgeInsets.symmetric(vertical: 10),
 | 
			
		||||
                    child: FilledButton(
 | 
			
		||||
                      onPressed: _register,
 | 
			
		||||
                      child: const Text('Register'),
 | 
			
		||||
                  )
 | 
			
		||||
                ),
 | 
			
		||||
                    )),
 | 
			
		||||
              ],
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,13 +6,16 @@ import 'package:fooder/client.dart';
 | 
			
		|||
import 'package:fooder/screens/add_meal.dart';
 | 
			
		||||
import 'dart:core';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DiaryWidget extends StatelessWidget {
 | 
			
		||||
  final Diary diary;
 | 
			
		||||
  final ApiClient apiClient;
 | 
			
		||||
  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
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
| 
						 | 
				
			
			@ -27,13 +30,15 @@ class DiaryWidget extends StatelessWidget {
 | 
			
		|||
                    const Spacer(),
 | 
			
		||||
                    Text(
 | 
			
		||||
                      "${diary.calories.toStringAsFixed(1)} kcal",
 | 
			
		||||
                  style: Theme.of(context).textTheme.headlineLarge!.copyWith(
 | 
			
		||||
                      style: Theme.of(context)
 | 
			
		||||
                          .textTheme
 | 
			
		||||
                          .headlineLarge!
 | 
			
		||||
                          .copyWith(
 | 
			
		||||
                            color: Theme.of(context).colorScheme.onSecondary,
 | 
			
		||||
                            fontWeight: FontWeight.bold,
 | 
			
		||||
                          ),
 | 
			
		||||
                    ),
 | 
			
		||||
              ]
 | 
			
		||||
            ),
 | 
			
		||||
                  ]),
 | 
			
		||||
              expandedHeight: 150,
 | 
			
		||||
              backgroundColor: Theme.of(context).colorScheme.secondary,
 | 
			
		||||
              shape: RoundedRectangleBorder(
 | 
			
		||||
| 
						 | 
				
			
			@ -65,13 +70,14 @@ class DiaryWidget extends StatelessWidget {
 | 
			
		|||
                    },
 | 
			
		||||
                    icon: const Icon(Icons.add),
 | 
			
		||||
                    style: ButtonStyle(
 | 
			
		||||
                    backgroundColor: MaterialStateProperty.all<Color>(Theme.of(context).colorScheme.secondary),
 | 
			
		||||
                    foregroundColor: MaterialStateProperty.all<Color>(Theme.of(context).colorScheme.onSecondary),
 | 
			
		||||
                      backgroundColor: MaterialStateProperty.all<Color>(
 | 
			
		||||
                          Theme.of(context).colorScheme.secondary),
 | 
			
		||||
                      foregroundColor: MaterialStateProperty.all<Color>(
 | 
			
		||||
                          Theme.of(context).colorScheme.onSecondary),
 | 
			
		||||
                    ),
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
              )
 | 
			
		||||
            ),
 | 
			
		||||
              )),
 | 
			
		||||
          SliverList(
 | 
			
		||||
            delegate: SliverChildListDelegate(
 | 
			
		||||
              [
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,6 @@ import 'package:fooder/models/entry.dart';
 | 
			
		|||
import 'package:fooder/widgets/macro.dart';
 | 
			
		||||
import 'dart:core';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EntryWidget extends StatelessWidget {
 | 
			
		||||
  final Entry entry;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,5 @@
 | 
			
		|||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MacroWidget extends StatelessWidget {
 | 
			
		||||
  final double? amount;
 | 
			
		||||
  final double? calories;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,13 +6,16 @@ import 'package:fooder/screens/edit_entry.dart';
 | 
			
		|||
import 'package:fooder/client.dart';
 | 
			
		||||
import 'dart:core';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MealWidget extends StatelessWidget {
 | 
			
		||||
  final Meal meal;
 | 
			
		||||
  final ApiClient apiClient;
 | 
			
		||||
  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
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,6 @@ import 'package:fooder/models/product.dart';
 | 
			
		|||
import 'package:fooder/widgets/macro.dart';
 | 
			
		||||
import 'dart:core';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProductWidget extends StatelessWidget {
 | 
			
		||||
  final Product product;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue