diff --git a/Dockerfile b/Dockerfile index 3d17ca4..830a5f2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,45 +1,13 @@ -FROM debian:stable-slim AS build-env +# BUILD +FROM node:16.14-alpine -# install all needed stuff -RUN apt-get update -RUN apt-get install -y curl git unzip +COPY ./build/web /app -# define variables -ARG FLUTTER_SDK=/usr/local/flutter -ARG FLUTTER_VERSION=3.10.5 -ARG APP=/app/ +WORKDIR /app/ -#clone flutter -RUN git clone https://github.com/flutter/flutter.git $FLUTTER_SDK -# change dir to current flutter folder and make a checkout to the specific version +RUN apk --no-cache add curl +RUN npm install --global http-server -# setup the flutter path as an enviromental variable -ENV PATH="$FLUTTER_SDK/bin:$FLUTTER_SDK/bin/cache/dart-sdk/bin:${PATH}" - -# Start to run Flutter commands -# doctor to see if all was installes ok -RUN flutter doctor -v - -# create folder to copy source code -RUN mkdir $APP -# copy source code to folder -COPY . $APP -# stup new folder as the working directory -WORKDIR $APP - -# Run build: 1 - clean, 2 - pub get, 3 - build web -RUN flutter clean -RUN flutter pub get -RUN flutter build web - -# once heare the app will be compiled and ready to deploy - -# use nginx to deploy -FROM nginx:1.25.2-alpine - -# copy the info of the builded web app to nginx -COPY --from=build-env /app/build/web /usr/share/nginx/html - -# Expose and run nginx EXPOSE 80 -CMD ["nginx", "-g", "daemon off;"] + +CMD ["npx", "http-server", "-p", "80"] diff --git a/Makefile b/Makefile index c52fb6f..9124452 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ endif .PHONY: build build: + flutter build web $(DOCKER_BUILD) -t registry.domandoman.xyz/fooder/app -f Dockerfile . .PHONY: push diff --git a/lib/components/app_bar.dart b/lib/components/app_bar.dart index 1023be7..d7b0eeb 100644 --- a/lib/components/app_bar.dart +++ b/lib/components/app_bar.dart @@ -11,6 +11,8 @@ class FAppBar extends StatelessWidget implements PreferredSizeWidget { padding: const EdgeInsets.symmetric(horizontal: 8), child: AppBar( backgroundColor: Colors.transparent, + shadowColor: Colors.transparent, + surfaceTintColor: Colors.transparent, elevation: 0, actions: actions, )); diff --git a/lib/components/blur_container.dart b/lib/components/blur_container.dart new file mode 100644 index 0000000..672ea52 --- /dev/null +++ b/lib/components/blur_container.dart @@ -0,0 +1,37 @@ +import 'package:flutter/material.dart'; +import 'package:blur/blur.dart'; + +class BlurContainer extends StatelessWidget { + final Widget? child; + final double? height; + final double? width; + + const BlurContainer({super.key, this.height, this.width, this.child}); + + @override + Widget build(BuildContext context) { + var theme = Theme.of(context); + var colorScheme = theme.colorScheme; + + var blured = Blur( + blur: 10, + blurColor: colorScheme.surface.withOpacity(0.1), + child: Container( + height: height, + width: width, + color: colorScheme.surface.withOpacity(0.1), + ), + ); + + if (child == null) { + return blured; + } + + return Stack( + children: [ + blured, + child!, + ], + ); + } +} diff --git a/lib/components/button.dart b/lib/components/button.dart index e66a97b..78dea61 100644 --- a/lib/components/button.dart +++ b/lib/components/button.dart @@ -27,20 +27,8 @@ class FButton extends StatelessWidget { child: Container( padding: EdgeInsets.symmetric(vertical: insidePadding), decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - colorScheme.primary.withOpacity(0.5), - colorScheme.secondary.withOpacity(0.5), - ], - ), borderRadius: BorderRadius.circular(4), - boxShadow: [ - BoxShadow( - color: colorScheme.primary.withOpacity(0.3), - blurRadius: 5, - offset: const Offset(0, 5), - ) - ], + color: colorScheme.surfaceTint.withOpacity(0.85), ), child: Center( child: Text( @@ -48,6 +36,7 @@ class FButton extends StatelessWidget { style: theme.textTheme.labelLarge!.copyWith( fontWeight: FontWeight.bold, fontSize: fontSize, + color: colorScheme.onPrimary, ), ), ), diff --git a/lib/components/date_picker.dart b/lib/components/date_picker.dart index 43b0180..1247a84 100644 --- a/lib/components/date_picker.dart +++ b/lib/components/date_picker.dart @@ -40,7 +40,7 @@ class FDateItemWidget extends StatelessWidget { width: 2, ), color: picked - ? colorScheme.onPrimary.withOpacity(0.25) + ? colorScheme.onSurfaceVariant.withOpacity(0.25) : Colors.transparent, ), child: Column( @@ -49,7 +49,7 @@ class FDateItemWidget extends StatelessWidget { Text( dayOfTheWeekMap[date.weekday]!, style: TextStyle( - color: colorScheme.onPrimary, + color: colorScheme.onSurfaceVariant, fontSize: picked ? 24 : 12, fontWeight: FontWeight.bold, ), @@ -57,7 +57,7 @@ class FDateItemWidget extends StatelessWidget { Text( '${date.day}.${date.month}', style: TextStyle( - color: colorScheme.onPrimary, + color: colorScheme.onSurfaceVariant, fontSize: picked ? 24 : 12, fontWeight: FontWeight.bold, ), @@ -128,7 +128,7 @@ class _FDatePickerWidgetState extends State { child: IconButton( icon: Icon( Icons.calendar_month, - color: colorScheme.onPrimary, + color: colorScheme.onSurfaceVariant, size: 20, ), onPressed: () { diff --git a/lib/components/dropdown.dart b/lib/components/dropdown.dart new file mode 100644 index 0000000..e280b63 --- /dev/null +++ b/lib/components/dropdown.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; + +class FDropdown extends StatelessWidget { + final String labelText; + final List> items; + final Function(T?) onChanged; + final T? value; + final double padding; + + const FDropdown( + {super.key, + required this.labelText, + this.padding = 8, + required this.items, + required this.onChanged, + this.value}); + + @override + Widget build(BuildContext context) { + var theme = Theme.of(context); + var colorScheme = theme.colorScheme; + + return Padding( + padding: EdgeInsets.symmetric(vertical: padding, horizontal: padding), + child: DropdownButtonFormField( + onChanged: onChanged, + items: items, + value: value, + decoration: InputDecoration( + labelText: labelText, + floatingLabelStyle: + theme.textTheme.bodyLarge!.copyWith(color: colorScheme.onSurface), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: colorScheme.primary), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: colorScheme.onPrimary), + ), + ), + ), + ); + } +} diff --git a/lib/components/floating_action_button.dart b/lib/components/floating_action_button.dart new file mode 100644 index 0000000..89cea7c --- /dev/null +++ b/lib/components/floating_action_button.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'package:fooder/components/blur_container.dart'; + +class FActionButton extends StatelessWidget { + final IconData icon; + final Function() onPressed; + final String tag; + + const FActionButton( + {super.key, + required this.icon, + required this.onPressed, + this.tag = 'fap'}); + + @override + Widget build(BuildContext context) { + var theme = Theme.of(context); + var colorScheme = theme.colorScheme; + + return Container( + height: 64, + width: 64, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(32), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(32), + child: BlurContainer( + height: 64, + width: 64, + child: SizedBox( + height: 64, + width: 64, + child: FloatingActionButton( + elevation: 0, + onPressed: onPressed, + heroTag: tag, + backgroundColor: Colors.transparent, + child: Icon( + icon, + color: colorScheme.onSurface, + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/components/navigation_bar.dart b/lib/components/navigation_bar.dart index 8e7a05b..f005857 100644 --- a/lib/components/navigation_bar.dart +++ b/lib/components/navigation_bar.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:blur/blur.dart'; +import 'package:flutter/widgets.dart'; +import 'package:fooder/components/blur_container.dart'; class FNavBar extends StatelessWidget { static const maxWidth = 920.0; @@ -7,61 +8,25 @@ class FNavBar extends StatelessWidget { final List children; final double height; - const FNavBar({super.key, required this.children, this.height = 56}); + const FNavBar({super.key, required this.children, this.height = 78}); @override Widget build(BuildContext context) { - var theme = Theme.of(context); - var colorScheme = theme.colorScheme; - var widthAvail = MediaQuery.of(context).size.width; // var width = widthAvail > maxWidth ? maxWidth : widthAvail; - - return SafeArea( - child: Padding( - padding: const EdgeInsets.all(12), - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(24), - boxShadow: [ - BoxShadow( - color: colorScheme.primary.withOpacity(0.3), - blurRadius: 5, - offset: const Offset(0, 5), - ) - ], + return SizedBox( + width: widthAvail, + height: height * children.length, + child: BlurContainer( + width: widthAvail, + height: height * children.length, + child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [ + ...children, + Container( + height: height / 3, + color: Colors.transparent, ), - child: ClipRRect( - borderRadius: BorderRadius.circular(24), - child: Stack( - children: [ - Blur( - blur: 10, - blurColor: colorScheme.primary.withOpacity(0.1), - child: Container( - width: widthAvail, - height: height * children.length, - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - colorScheme.primary.withOpacity(0.1), - colorScheme.secondary.withOpacity(0.1), - ], - ), - ), - ), - ), - SizedBox( - width: widthAvail, - height: height * children.length, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: children, - ), - ), - ], - )), - ), + ]), ), ); } diff --git a/lib/components/sliver.dart b/lib/components/sliver.dart index 16d52dd..02b551d 100644 --- a/lib/components/sliver.dart +++ b/lib/components/sliver.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:blur/blur.dart'; +import 'package:fooder/components/blur_container.dart'; class ClipShadowPath extends StatelessWidget { final Shadow shadow; @@ -56,28 +56,11 @@ class BackgroundWave extends StatelessWidget { return SizedBox( height: height, - child: ClipShadowPath( + child: ClipPath( clipper: BackgroundWaveClipper(), - shadow: BoxShadow( - blurRadius: 5, - color: colorScheme.primary.withOpacity(0.3), - offset: const Offset(0, 5), - ), - child: Blur( - blur: 10, - blurColor: colorScheme.primary.withOpacity(0.1), - child: Container( - width: MediaQuery.of(context).size.width, - height: height, - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - colorScheme.primary.withOpacity(0.1), - colorScheme.secondary.withOpacity(0.1), - ], - ), - ), - ), + child: BlurContainer( + width: MediaQuery.of(context).size.width, + height: height, ), ), ); @@ -131,8 +114,9 @@ class BackgroundWaveClipper extends CustomClipper { } class FSliverAppBar extends SliverPersistentHeaderDelegate { + final double preferredHeight; final Widget child; - const FSliverAppBar({required this.child}); + const FSliverAppBar({required this.child, this.preferredHeight = 220}); @override Widget build( @@ -147,8 +131,11 @@ class FSliverAppBar extends SliverPersistentHeaderDelegate { return Stack( children: [ - const BackgroundWave( - height: 280, + // const BackgroundWave( + // height: preferredHeight, + // ), + BlurContainer( + height: preferredHeight, ), Positioned( top: offset, @@ -161,10 +148,10 @@ class FSliverAppBar extends SliverPersistentHeaderDelegate { } @override - double get maxExtent => 280; + double get maxExtent => preferredHeight; @override - double get minExtent => 140; + double get minExtent => preferredHeight / 2; @override bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) => diff --git a/lib/components/text.dart b/lib/components/text.dart index 7044f8e..a8114d1 100644 --- a/lib/components/text.dart +++ b/lib/components/text.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; class FTextInput extends StatelessWidget { final String labelText; @@ -8,6 +9,9 @@ class FTextInput extends StatelessWidget { final bool autofocus; final bool obscureText; final Function(String)? onFieldSubmitted; + final TextInputType? keyboardType; + final List? inputFormatters; + final Function(String)? onChanged; const FTextInput( {super.key, @@ -17,7 +21,10 @@ class FTextInput extends StatelessWidget { this.autofillHints, this.autofocus = false, this.onFieldSubmitted, - this.obscureText = false}); + this.obscureText = false, + this.keyboardType, + this.inputFormatters, + this.onChanged}); @override Widget build(BuildContext context) { @@ -30,6 +37,8 @@ class FTextInput extends StatelessWidget { obscureText: obscureText, decoration: InputDecoration( labelText: labelText, + floatingLabelStyle: + theme.textTheme.bodyLarge!.copyWith(color: colorScheme.onSurface), enabledBorder: OutlineInputBorder( borderSide: BorderSide(color: colorScheme.primary), ), @@ -41,6 +50,9 @@ class FTextInput extends StatelessWidget { autofillHints: autofillHints, autofocus: autofocus, onFieldSubmitted: onFieldSubmitted, + keyboardType: keyboardType, + inputFormatters: inputFormatters, + onChanged: onChanged, ), ); } diff --git a/lib/main.dart b/lib/main.dart index 785f740..534398a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:fooder/screens/login.dart'; import 'package:fooder/client.dart'; -import 'package:flex_color_scheme/flex_color_scheme.dart'; +import 'package:fooder/theme.dart'; class MyApp extends StatelessWidget { const MyApp({super.key}); @@ -10,8 +10,8 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( title: 'FOODER', - theme: FlexThemeData.light(scheme: FlexScheme.brandBlue), - darkTheme: FlexThemeData.dark(scheme: FlexScheme.brandBlue), + theme: MainTheme.light(), + darkTheme: MainTheme.dark(), themeMode: ThemeMode.system, debugShowCheckedModeBanner: false, home: LoginScreen( diff --git a/lib/screens/add_entry.dart b/lib/screens/add_entry.dart index a996fae..9e08327 100644 --- a/lib/screens/add_entry.dart +++ b/lib/screens/add_entry.dart @@ -5,6 +5,9 @@ import 'package:fooder/models/product.dart'; import 'package:fooder/models/diary.dart'; import 'package:fooder/models/meal.dart'; import 'package:fooder/widgets/product.dart'; +import 'package:fooder/components/text.dart'; +import 'package:fooder/components/dropdown.dart'; +import 'package:fooder/components/floating_action_button.dart'; import 'package:fooder/screens/add_product.dart'; import 'package:simple_barcode_scanner/simple_barcode_scanner.dart'; @@ -132,7 +135,8 @@ class _AddEntryScreen extends BasedState { constraints: const BoxConstraints(maxWidth: 720), padding: const EdgeInsets.all(10), child: ListView(children: [ - DropdownButton( + FDropdown( + labelText: 'Meal', value: meal, // Callback that sets the selected popup menu item. onChanged: (Meal? meal) { @@ -151,19 +155,15 @@ class _AddEntryScreen extends BasedState { ), ], ), - TextFormField( - decoration: const InputDecoration( - labelText: 'Product name', - ), + FTextInput( + labelText: 'Product name', controller: productNameController, onChanged: (_) => _getProducts(), onFieldSubmitted: (_) => _addEntry(), autofocus: true, ), - TextFormField( - decoration: const InputDecoration( - labelText: 'Grams', - ), + FTextInput( + labelText: 'Grams', keyboardType: const TextInputType.numberWithOptions(decimal: true), inputFormatters: [ @@ -212,14 +212,15 @@ class _AddEntryScreen extends BasedState { floatingActionButton: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - FloatingActionButton( + FActionButton( onPressed: _findProductByBarCode, - heroTag: null, - child: const Icon(Icons.photo_camera), + icon: Icons.photo_camera, ), - FloatingActionButton( + const SizedBox(width: 10), + FActionButton( onPressed: _addEntry, - child: const Icon(Icons.add), + icon: Icons.library_add, + tag: "fap2", ), ], ), diff --git a/lib/screens/add_meal.dart b/lib/screens/add_meal.dart index cbde4af..4de8edc 100644 --- a/lib/screens/add_meal.dart +++ b/lib/screens/add_meal.dart @@ -3,6 +3,8 @@ import 'package:fooder/screens/based.dart'; import 'package:fooder/models/diary.dart'; import 'package:fooder/models/preset.dart'; import 'package:fooder/widgets/preset.dart'; +import 'package:fooder/components/text.dart'; +import 'package:fooder/components/floating_action_button.dart'; class AddMealScreen extends BasedScreen { final Diary diary; @@ -14,7 +16,7 @@ class AddMealScreen extends BasedScreen { State createState() => _AddMealScreen(); } -class _AddMealScreen extends State { +class _AddMealScreen extends BasedState { final nameController = TextEditingController(); final presetNameController = TextEditingController(); bool nameChanged = false; @@ -37,7 +39,7 @@ class _AddMealScreen extends State { void initState() { super.initState(); setState(() { - nameController.text = "Meal ${widget.diary.meals.length}"; + nameController.text = "Meal ${widget.diary.meals.length + 1}"; }); _getPresets(); } @@ -54,15 +56,6 @@ class _AddMealScreen extends State { ); } - void showError(String message) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(message, textAlign: TextAlign.center), - backgroundColor: Theme.of(context).colorScheme.error, - ), - ); - } - Future _addMeal() async { await widget.apiClient.addMeal( name: nameController.text, @@ -121,28 +114,21 @@ class _AddMealScreen extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - title: Text("πŸ…΅πŸ…ΎπŸ…ΎπŸ…³πŸ…΄πŸ†", style: logoStyle(context)), - ), + appBar: appBar(), body: Center( child: Container( constraints: const BoxConstraints(maxWidth: 720), padding: const EdgeInsets.all(10), child: ListView(children: [ - TextFormField( - decoration: const InputDecoration( - labelText: 'Meal name', - ), + FTextInput( + labelText: 'Meal name', controller: nameController, onChanged: (_) => setState(() { nameChanged = true; }), ), - TextFormField( - decoration: const InputDecoration( - hintText: 'Search presets', - ), + FTextInput( + labelText: 'Search presets', controller: presetNameController, onChanged: (_) => _getPresets(), ), @@ -166,9 +152,9 @@ class _AddMealScreen extends State { ]), ), ), - floatingActionButton: FloatingActionButton( + floatingActionButton: FActionButton( onPressed: _addMealFromPreset, - child: const Icon(Icons.add), + icon: Icons.playlist_add_rounded, ), ); } diff --git a/lib/screens/add_product.dart b/lib/screens/add_product.dart index 9eb46fa..944c7ab 100644 --- a/lib/screens/add_product.dart +++ b/lib/screens/add_product.dart @@ -2,6 +2,9 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:fooder/screens/based.dart'; import 'package:fooder/models/product.dart'; +import 'package:fooder/widgets/product.dart'; +import 'package:fooder/components/text.dart'; +import 'package:fooder/components/floating_action_button.dart'; class AddProductScreen extends BasedScreen { const AddProductScreen({super.key, required super.apiClient}); @@ -10,7 +13,7 @@ class AddProductScreen extends BasedScreen { State createState() => _AddProductScreen(); } -class _AddProductScreen extends State { +class _AddProductScreen extends BasedState { final nameController = TextEditingController(); final carbController = TextEditingController(); final fatController = TextEditingController(); @@ -34,15 +37,6 @@ class _AddProductScreen extends State { ); } - void showError(String message) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(message, textAlign: TextAlign.center), - backgroundColor: Theme.of(context).colorScheme.error, - ), - ); - } - Future _parseDouble(String text, String name, {bool silent = false}) async { try { @@ -113,25 +107,21 @@ class _AddProductScreen extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - title: Text("πŸ…΅πŸ…ΎπŸ…ΎπŸ…³πŸ…΄πŸ†", style: logoStyle(context)), - ), + appBar: appBar(), body: Center( child: Container( constraints: const BoxConstraints(maxWidth: 720), padding: const EdgeInsets.all(10), child: Column(children: [ - TextFormField( - decoration: const InputDecoration( - labelText: 'Product name', - ), + FTextInput( + labelText: 'Product name', controller: nameController, + onChanged: (String value) { + setState(() {}); + }, ), - TextFormField( - decoration: const InputDecoration( - labelText: 'Carbs', - ), + FTextInput( + labelText: 'Carbs', keyboardType: const TextInputType.numberWithOptions(decimal: true), inputFormatters: [ @@ -143,10 +133,8 @@ class _AddProductScreen extends State { setState(() {}); }, ), - TextFormField( - decoration: const InputDecoration( - labelText: 'Fat', - ), + FTextInput( + labelText: 'Fat', keyboardType: const TextInputType.numberWithOptions(decimal: true), inputFormatters: [ @@ -158,10 +146,8 @@ class _AddProductScreen extends State { setState(() {}); }, ), - TextFormField( - decoration: const InputDecoration( - labelText: 'Protein', - ), + FTextInput( + labelText: 'Protein', keyboardType: const TextInputType.numberWithOptions(decimal: true), inputFormatters: [ @@ -173,10 +159,8 @@ class _AddProductScreen extends State { setState(() {}); }, ), - TextFormField( - decoration: const InputDecoration( - labelText: 'Fiber', - ), + FTextInput( + labelText: 'Fiber', keyboardType: const TextInputType.numberWithOptions(decimal: true), inputFormatters: [ @@ -188,15 +172,30 @@ class _AddProductScreen extends State { setState(() {}); }, ), - Text( - "${calculateCalories().toStringAsFixed(2)} kcal", - textAlign: TextAlign.right, - ), + ProductWidget( + product: Product( + id: 0, + name: nameController.text, + carb: double.tryParse( + carbController.text.replaceAll(",", ".")) ?? + 0.0, + fat: double.tryParse( + fatController.text.replaceAll(",", ".")) ?? + 0.0, + protein: double.tryParse( + proteinController.text.replaceAll(",", ".")) ?? + 0.0, + fiber: double.tryParse( + fiberController.text.replaceAll(",", ".")) ?? + 0.0, + calories: calculateCalories(), + ), + ) ])), ), - floatingActionButton: FloatingActionButton( + floatingActionButton: FActionButton( onPressed: _addProduct, - child: const Icon(Icons.add), + icon: Icons.save, ), ); } diff --git a/lib/screens/based.dart b/lib/screens/based.dart index 205a958..0a1269a 100644 --- a/lib/screens/based.dart +++ b/lib/screens/based.dart @@ -43,7 +43,7 @@ abstract class BasedState extends State { IconButton( icon: Icon( Icons.logout, - color: Theme.of(context).colorScheme.onPrimary, + color: Theme.of(context).colorScheme.onSurfaceVariant, ), onPressed: _logout, ), @@ -60,28 +60,28 @@ abstract class BasedState extends State { IconButton( icon: Icon( Icons.menu_book, - color: Theme.of(context).colorScheme.onPrimary, + color: Theme.of(context).colorScheme.onSurfaceVariant, ), onPressed: backToDiary, ), IconButton( icon: Icon( Icons.dinner_dining, - color: Theme.of(context).colorScheme.onPrimary, + color: Theme.of(context).colorScheme.onSurfaceVariant, ), onPressed: () {}, ), IconButton( icon: Icon( Icons.lunch_dining, - color: Theme.of(context).colorScheme.onPrimary, + color: Theme.of(context).colorScheme.onSurfaceVariant, ), onPressed: () {}, ), IconButton( icon: Icon( Icons.person, - color: Theme.of(context).colorScheme.onPrimary, + color: Theme.of(context).colorScheme.onSurfaceVariant, ), onPressed: () {}, ), diff --git a/lib/screens/edit_entry.dart b/lib/screens/edit_entry.dart index d35ec74..3eb4333 100644 --- a/lib/screens/edit_entry.dart +++ b/lib/screens/edit_entry.dart @@ -5,6 +5,8 @@ import 'package:fooder/models/product.dart'; import 'package:fooder/models/entry.dart'; import 'package:fooder/widgets/product.dart'; import 'package:fooder/screens/add_product.dart'; +import 'package:fooder/components/text.dart'; +import 'package:fooder/components/floating_action_button.dart'; import 'package:simple_barcode_scanner/simple_barcode_scanner.dart'; class EditEntryScreen extends BasedScreen { @@ -17,7 +19,7 @@ class EditEntryScreen extends BasedScreen { State createState() => _EditEntryScreen(); } -class _EditEntryScreen extends State { +class _EditEntryScreen extends BasedState { final gramsController = TextEditingController(); final productNameController = TextEditingController(); List products = []; @@ -53,15 +55,6 @@ class _EditEntryScreen extends State { }); } - void showError(String message) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(message, textAlign: TextAlign.center), - backgroundColor: Theme.of(context).colorScheme.error, - ), - ); - } - Future _parseDouble(String text, String name) async { try { return double.parse(text.replaceAll(",", ".")); @@ -123,27 +116,20 @@ class _EditEntryScreen extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar( - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - title: Text("πŸ…΅πŸ…ΎπŸ…ΎπŸ…³πŸ…΄πŸ†", style: logoStyle(context)), - ), + appBar: appBar(), body: Center( child: Container( constraints: const BoxConstraints(maxWidth: 720), padding: const EdgeInsets.all(10), child: ListView(children: [ - TextFormField( - decoration: const InputDecoration( - labelText: 'Product name', - ), + FTextInput( + labelText: 'Product name', controller: productNameController, onChanged: (_) => _getProducts(), autofocus: true, ), - TextFormField( - decoration: const InputDecoration( - labelText: 'Grams', - ), + FTextInput( + labelText: 'Grams', keyboardType: const TextInputType.numberWithOptions(decimal: true), inputFormatters: [ @@ -190,20 +176,21 @@ class _EditEntryScreen extends State { floatingActionButton: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - FloatingActionButton( + FActionButton( onPressed: _findProductByBarCode, - heroTag: null, - child: const Icon(Icons.photo_camera), + icon: Icons.photo_camera, ), - FloatingActionButton( + const SizedBox(width: 10), + FActionButton( onPressed: _deleteEntry, - heroTag: null, - child: const Icon(Icons.delete), + tag: "fap1", + icon: Icons.delete, ), - FloatingActionButton( + const SizedBox(width: 10), + FActionButton( onPressed: _saveEntry, - heroTag: null, - child: const Icon(Icons.save), + tag: "fap2", + icon: Icons.save, ), ], ), diff --git a/lib/screens/main.dart b/lib/screens/main.dart index ffbf32e..19eb232 100644 --- a/lib/screens/main.dart +++ b/lib/screens/main.dart @@ -1,12 +1,13 @@ import 'package:flutter/material.dart'; import 'package:fooder/screens/based.dart'; import 'package:fooder/screens/add_entry.dart'; +import 'package:fooder/screens/add_meal.dart'; import 'package:fooder/models/diary.dart'; import 'package:fooder/widgets/summary.dart'; import 'package:fooder/widgets/meal.dart'; import 'package:fooder/components/sliver.dart'; import 'package:fooder/components/date_picker.dart'; -import 'package:blur/blur.dart'; +import 'package:fooder/components/floating_action_button.dart'; class MainScreen extends BasedScreen { const MainScreen({super.key, required super.apiClient}); @@ -43,6 +44,10 @@ class _MainScreen extends BasedState { } Future _addEntry() async { + if (diary == null) { + return; + } + await Navigator.push( context, MaterialPageRoute( @@ -52,60 +57,20 @@ class _MainScreen extends BasedState { ).then((_) => _asyncInitState()); } - Widget floatingActionButton(BuildContext context) { - var theme = Theme.of(context); - var colorScheme = theme.colorScheme; + Future _addMeal(context) async { + if (diary == null) { + return; + } - return Container( - height: 64, - width: 64, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(32), - boxShadow: [ - BoxShadow( - color: colorScheme.primary.withOpacity(0.3), - blurRadius: 5, - offset: const Offset(0, 5), - ) - ], - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(32), - child: Stack( - children: [ - Blur( - blur: 10, - blurColor: colorScheme.primary.withOpacity(0.1), - child: Container( - height: 64, - width: 64, - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - colorScheme.primary.withOpacity(0.1), - colorScheme.secondary.withOpacity(0.1), - ], - ), - ), - ), - ), - SizedBox( - height: 64, - width: 64, - child: FloatingActionButton( - elevation: 0, - onPressed: _addEntry, - backgroundColor: Colors.transparent, - child: Icon( - Icons.library_add, - color: colorScheme.onPrimary, - ), - ), - ), - ], + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AddMealScreen( + apiClient: widget.apiClient, + diary: diary!, ), ), - ); + ).then((_) => _asyncInitState()); } @override @@ -133,7 +98,9 @@ class _MainScreen extends BasedState { apiClient: widget.apiClient, refreshParent: _asyncInitState, initiallyExpanded: i == 0, + showText: showText, ), + const SizedBox(height: 200), ], ), ), @@ -149,7 +116,18 @@ class _MainScreen extends BasedState { appBar: appBar(), bottomNavigationBar: navBar(), floatingActionButtonLocation: FloatingActionButtonLocation.endFloat, - floatingActionButton: floatingActionButton(context), + floatingActionButton: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + FActionButton( + icon: Icons.playlist_add, + onPressed: () => _addMeal(context), + ), + const SizedBox(width: 10), + FActionButton( + icon: Icons.library_add, onPressed: _addEntry, tag: "fap2"), + ], + ), ); } } diff --git a/lib/screens/meal.dart b/lib/screens/meal.dart deleted file mode 100644 index 48defcb..0000000 --- a/lib/screens/meal.dart +++ /dev/null @@ -1,181 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:fooder/screens/based.dart'; -import 'package:fooder/models/meal.dart'; -import 'package:fooder/widgets/macro.dart'; - -class MealScreen extends BasedScreen { - final Meal meal; - final Function() refresh; - - const MealScreen( - {super.key, - required super.apiClient, - required this.refresh, - required this.meal}); - - @override - State createState() => _AddMealScreen(); -} - -class _AddMealScreen extends State { - Future saveMeal(context) async { - TextEditingController textFieldController = TextEditingController(); - textFieldController.text = widget.meal.name; - - showDialog( - context: context, - builder: (context) { - return AlertDialog( - title: const Text('Save Meal'), - content: TextField( - controller: textFieldController, - decoration: const InputDecoration(hintText: "Meal template name"), - ), - actions: [ - IconButton( - icon: const Icon(Icons.cancel), - onPressed: () { - Navigator.pop(context); - }, - ), - IconButton( - icon: const Icon(Icons.save), - onPressed: () { - widget.apiClient - .saveMeal(widget.meal, textFieldController.text); - Navigator.pop(context); - }, - ), - ], - ); - }, - ); - } - - Future _deleteMeal(Meal meal) async { - await widget.apiClient.deleteMeal(meal.id); - } - - Future deleteMeal(context) async { - showDialog( - context: context, - builder: (context) { - return AlertDialog( - title: const Text('Confirm deletion of the meal'), - actions: [ - IconButton( - icon: const Icon(Icons.cancel), - onPressed: () { - Navigator.pop(context); - }, - ), - IconButton( - icon: const Icon(Icons.delete), - onPressed: () { - _deleteMeal(widget.meal); - Navigator.pop(context); - Navigator.pop(context); - widget.refresh(); - }, - ), - ], - ); - }, - ); - } - - Widget buildButton(Icon icon, String text, Function() onPressed) { - return Card( - child: ListTile( - onTap: onPressed, - title: Container( - padding: const EdgeInsets.all(8), - child: Row( - children: [ - IconButton( - icon: icon, - onPressed: onPressed, - ), - const Spacer(), - Text(text), - ], - ), - ), - ), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - title: Text("πŸ…΅πŸ…ΎπŸ…ΎπŸ…³πŸ…΄πŸ†", style: logoStyle(context)), - ), - body: Center( - child: Container( - constraints: const BoxConstraints(maxWidth: 720), - padding: const EdgeInsets.all(10), - child: CustomScrollView(slivers: [ - SliverAppBar( - title: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - widget.meal.name, - style: Theme.of(context) - .textTheme - .headlineLarge! - .copyWith( - color: Theme.of(context).colorScheme.onSecondary, - fontWeight: FontWeight.bold, - ), - ), - const Spacer(), - Text( - "${widget.meal.calories.toStringAsFixed(1)} kcal", - 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( - borderRadius: BorderRadius.circular(8), - ), - floating: true, - flexibleSpace: FlexibleSpaceBar( - title: MacroWidget( - protein: widget.meal.protein, - carb: widget.meal.carb, - fat: widget.meal.fat, - style: Theme.of(context).textTheme.bodyMedium!.copyWith( - color: Theme.of(context).colorScheme.onSecondary, - fontWeight: FontWeight.bold, - ), - ), - )), - SliverList( - delegate: SliverChildListDelegate([ - buildButton( - const Icon(Icons.save), - "Save as preset", - () => saveMeal(context), - ), - buildButton( - const Icon(Icons.delete), - "Delete", - () => deleteMeal(context), - ), - ])) - ]), - ), - ), - ); - } -} diff --git a/lib/theme.dart b/lib/theme.dart new file mode 100644 index 0000000..534c088 --- /dev/null +++ b/lib/theme.dart @@ -0,0 +1,51 @@ +import 'package:flex_color_scheme/flex_color_scheme.dart'; +import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; + +class MainTheme { + static ThemeData light() { + return FlexThemeData.light( + scheme: FlexScheme.brandBlue, + surfaceMode: FlexSurfaceMode.levelSurfacesLowScaffold, + blendLevel: 40, + subThemesData: const FlexSubThemesData( + blendOnLevel: 40, + useTextTheme: true, + useM2StyleDividerInM3: true, + alignedDropdown: true, + useInputDecoratorThemeInDialogs: true, + ), + keyColors: const FlexKeyColors( + useSecondary: true, + useTertiary: true, + ), + visualDensity: FlexColorScheme.comfortablePlatformDensity, + useMaterial3: true, + swapLegacyOnMaterial3: true, + fontFamily: GoogleFonts.notoSans().fontFamily, + ).copyWith( + dividerColor: Colors.transparent, + ); + } + + static ThemeData dark() { + return FlexThemeData.dark( + scheme: FlexScheme.brandBlue, + surfaceMode: FlexSurfaceMode.levelSurfacesLowScaffold, + blendLevel: 40, + subThemesData: const FlexSubThemesData( + blendOnLevel: 20, + useTextTheme: true, + useM2StyleDividerInM3: true, + alignedDropdown: true, + useInputDecoratorThemeInDialogs: true, + ), + visualDensity: FlexColorScheme.comfortablePlatformDensity, + useMaterial3: true, + swapLegacyOnMaterial3: true, + fontFamily: GoogleFonts.notoSans().fontFamily, + ).copyWith( + dividerColor: Colors.transparent, + ); + } +} diff --git a/lib/widgets/diary.dart b/lib/widgets/diary.dart deleted file mode 100644 index ad219ba..0000000 --- a/lib/widgets/diary.dart +++ /dev/null @@ -1,97 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:fooder/models/diary.dart'; -import 'package:fooder/widgets/meal.dart'; -import 'package:fooder/widgets/macro.dart'; -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}); - - @override - Widget build(BuildContext context) { - return Container( - padding: const EdgeInsets.all(8), - child: CustomScrollView( - slivers: [ - SliverAppBar( - title: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const Spacer(), - Text( - "${diary.calories.toStringAsFixed(1)} kcal", - 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( - borderRadius: BorderRadius.circular(8), - ), - floating: true, - flexibleSpace: FlexibleSpaceBar( - title: MacroWidget( - protein: diary.protein, - carb: diary.carb, - fat: diary.fat, - style: Theme.of(context).textTheme.bodyMedium!.copyWith( - color: Theme.of(context).colorScheme.onSecondary, - fontWeight: FontWeight.bold, - ), - ), - )), - SliverToBoxAdapter( - child: Container( - padding: const EdgeInsets.all(8), - child: TextButton( - onPressed: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AddMealScreen( - apiClient: apiClient, - diary: diary, - ), - ), - ).then((_) { - refreshParent(); - }); - }, - child: const Text("Add Meal"), - ), - ), - ), - SliverList( - delegate: SliverChildListDelegate( - [ - for (var (i, meal) in diary.meals.indexed) - MealWidget( - meal: meal, - apiClient: apiClient, - refreshParent: refreshParent, - initiallyExpanded: i == 0, - ), - ], - ), - ), - ], - ), - ); - } -} diff --git a/lib/widgets/entry.dart b/lib/widgets/entry.dart index c73552e..b572b0f 100644 --- a/lib/widgets/entry.dart +++ b/lib/widgets/entry.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:fooder/models/entry.dart'; -import 'package:fooder/widgets/macroEntry.dart'; +import 'package:fooder/widgets/macro.dart'; import 'dart:core'; class EntryHeader extends StatelessWidget { @@ -12,14 +12,17 @@ class EntryHeader extends StatelessWidget { Widget build(BuildContext context) { return Row( children: [ - Padding( - padding: const EdgeInsets.all(8), - child: Text( - entry.product.name, - style: Theme.of(context).textTheme.bodyLarge!.copyWith( - color: Theme.of(context).colorScheme.onPrimary, - fontWeight: FontWeight.bold, - ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(8), + child: Text( + entry.product.name, + overflow: TextOverflow.fade, + style: Theme.of(context).textTheme.bodyLarge!.copyWith( + color: Theme.of(context).colorScheme.onSurface, + fontWeight: FontWeight.bold, + ), + ), ), ), const Spacer(), @@ -28,7 +31,7 @@ class EntryHeader extends StatelessWidget { child: Text( "${entry.grams.toStringAsFixed(0)} g", style: Theme.of(context).textTheme.bodyMedium!.copyWith( - color: Theme.of(context).colorScheme.onPrimary, + color: Theme.of(context).colorScheme.onSurface, ), ), ), diff --git a/lib/widgets/macro.dart b/lib/widgets/macro.dart index d4f7b2c..8b805b6 100644 --- a/lib/widgets/macro.dart +++ b/lib/widgets/macro.dart @@ -1,122 +1,163 @@ import 'package:flutter/material.dart'; +import 'dart:core'; -class MacroWidget extends StatelessWidget { - final double? amount; - final double? calories; - final double? fiber; - final double protein; - final double carb; - final double fat; - final TextStyle style; - final Widget? child; +class MacroHeaderWidget extends StatelessWidget { + static const double padY = 4; + static const double padX = 8; - const MacroWidget({ + final bool? fiber; + final bool? calories; + final Alignment alignment; + + const MacroHeaderWidget({ super.key, - this.calories, - this.amount, - this.child, - this.fiber, - required this.protein, - required this.carb, - required this.fat, - required this.style, + this.fiber = false, + this.calories = false, + this.alignment = Alignment.centerLeft, }); @override Widget build(BuildContext context) { - var elements = [ - Expanded( - flex: 1, - child: Text( - "C: ${carb.toStringAsFixed(1)}g", - style: style, - textAlign: TextAlign.center, + var elements = [ + "C(g)", + "F(g)", + "P(g)", + ]; + + if (fiber == true) { + elements.add( + "f(g)", + ); + } + + if (calories == true) { + elements.add( + "kcal", + ); + } + + var children = []; + + if (alignment == Alignment.centerRight) { + children.add(const Spacer()); + } + + for (var element in elements) { + children.add( + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 2, + ), + child: SizedBox( + width: 55, + child: Text( + element, + style: Theme.of(context).textTheme.bodyLarge!.copyWith( + color: Theme.of(context).colorScheme.onSurface, + ), + textAlign: TextAlign.center, + ), + ), ), + ); + } + + if (alignment == Alignment.centerLeft) { + children.add(const Spacer()); + } + + return Padding( + padding: const EdgeInsets.symmetric( + vertical: padY, + horizontal: padX, ), - Expanded( - flex: 1, - child: Text( - "F: ${fat.toStringAsFixed(1)}g", - style: style, - textAlign: TextAlign.center, - ), - ), - Expanded( - flex: 1, - child: Text( - "P: ${protein.toStringAsFixed(1)}g", - style: style, - textAlign: TextAlign.center, - ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: children, ), + ); + } +} + +class MacroEntryWidget extends StatelessWidget { + static const double padY = 4; + static const double padX = 8; + + final double protein; + final double carb; + final double fat; + final double? fiber; + final double? calories; + final Alignment alignment; + + const MacroEntryWidget({ + super.key, + required this.protein, + required this.carb, + required this.fat, + this.fiber, + this.calories, + this.alignment = Alignment.centerLeft, + }); + + @override + Widget build(BuildContext context) { + var elements = [ + (carb.toStringAsFixed(1)), + (fat.toStringAsFixed(1)), + (protein.toStringAsFixed(1)), ]; if (fiber != null) { elements.add( - Expanded( - flex: 1, - child: Text( - "f: ${fiber!.toStringAsFixed(1)}g", - style: style, - textAlign: TextAlign.center, - ), - ), + fiber!.toStringAsFixed(1), ); } if (calories != null) { elements.add( - Expanded( - flex: 1, - child: Text( - "${calories!.toStringAsFixed(1)} kcal", - style: style, - textAlign: TextAlign.center, + calories!.toStringAsFixed(0), + ); + } + + var children = []; + + if (alignment == Alignment.centerRight) { + children.add(const Spacer()); + } + + for (var element in elements) { + children.add( + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 2, + ), + child: SizedBox( + width: 55, + child: Text( + element, + style: Theme.of(context).textTheme.bodyLarge!.copyWith( + color: Theme.of(context).colorScheme.onSurface, + ), + textAlign: TextAlign.center, + ), ), ), ); } - if (amount != null) { - elements.add( - Expanded( - flex: 1, - child: Text( - "${amount!.toStringAsFixed(1)}g", - style: style, - textAlign: TextAlign.center, - ), - ), - ); - } - - if (child != null) { - elements.add( - Expanded( - flex: 1, - child: child!, - ), - ); - } - - if (elements.length < 4) { - elements.add( - const Expanded( - flex: 1, - child: Text(""), - ), - ); + if (alignment == Alignment.centerLeft) { + children.add(const Spacer()); } return Padding( - padding: const EdgeInsets.only( - top: 4.0, - bottom: 4.0, - left: 8.0, - right: 8.0, + padding: const EdgeInsets.symmetric( + vertical: padY, + horizontal: padX, ), child: Row( - children: elements, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: children, ), ); } diff --git a/lib/widgets/macroEntry.dart b/lib/widgets/macroEntry.dart deleted file mode 100644 index 0838350..0000000 --- a/lib/widgets/macroEntry.dart +++ /dev/null @@ -1,148 +0,0 @@ -import 'package:flutter/material.dart'; -import 'dart:core'; - -class MacroHeaderWidget extends StatelessWidget { - static const double PAD_Y = 4; - static const double PAD_X = 8; - - final bool? fiber; - final bool? calories; - - const MacroHeaderWidget({ - super.key, - this.fiber = false, - this.calories = false, - }); - - @override - Widget build(BuildContext context) { - var elements = [ - "C(g)", - "F(g)", - "P(g)", - ]; - - if (fiber == true) { - elements.add( - "F(g)", - ); - } - - if (calories == true) { - elements.add( - "kcal", - ); - } - - var children = []; - - for (var element in elements) { - children.add( - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 2, - ), - child: SizedBox( - width: 55, - child: Text( - element, - style: Theme.of(context).textTheme.bodyLarge!.copyWith( - color: Theme.of(context).colorScheme.onPrimary, - ), - textAlign: TextAlign.center, - ), - ), - ), - ); - } - - children.add(const Spacer()); - - return Padding( - padding: const EdgeInsets.symmetric( - vertical: PAD_Y, - horizontal: PAD_X, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: children, - ), - ); - } -} - -class MacroEntryWidget extends StatelessWidget { - static const double PAD_Y = 4; - static const double PAD_X = 8; - - final double protein; - final double carb; - final double fat; - final double? fiber; - final double? calories; - - const MacroEntryWidget({ - super.key, - required this.protein, - required this.carb, - required this.fat, - this.fiber, - this.calories, - }); - - @override - Widget build(BuildContext context) { - var elements = [ - (carb.toStringAsFixed(1)), - (fat.toStringAsFixed(1)), - (protein.toStringAsFixed(1)), - ]; - - if (fiber != null) { - elements.add( - fiber!.toStringAsFixed(1), - ); - } - - if (calories != null) { - elements.add( - calories!.toStringAsFixed(0), - ); - } - - var children = []; - - for (var element in elements) { - children.add( - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 2, - ), - child: SizedBox( - width: 55, - child: Text( - element, - style: Theme.of(context).textTheme.bodyLarge!.copyWith( - color: Theme.of(context).colorScheme.onPrimary, - ), - textAlign: TextAlign.center, - ), - ), - ), - ); - } - - children.add(const Spacer()); - - return Padding( - padding: const EdgeInsets.symmetric( - vertical: PAD_Y, - horizontal: PAD_X, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: children, - ), - ); - } -} diff --git a/lib/widgets/meal.dart b/lib/widgets/meal.dart index 09d2bde..24430c8 100644 --- a/lib/widgets/meal.dart +++ b/lib/widgets/meal.dart @@ -1,9 +1,8 @@ import 'package:flutter/material.dart'; import 'package:fooder/models/meal.dart'; import 'package:fooder/widgets/entry.dart'; -import 'package:fooder/widgets/macroEntry.dart'; +import 'package:fooder/widgets/macro.dart'; import 'package:fooder/screens/edit_entry.dart'; -import 'package:fooder/screens/meal.dart'; import 'package:fooder/client.dart'; import 'dart:core'; @@ -16,14 +15,17 @@ class MealHeader extends StatelessWidget { Widget build(BuildContext context) { return Row( children: [ - Padding( - padding: const EdgeInsets.all(8), - child: Text( - meal.name, - style: Theme.of(context).textTheme.headlineSmall!.copyWith( - color: Theme.of(context).colorScheme.onPrimary, - fontWeight: FontWeight.bold, - ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(8), + child: Text( + meal.name, + overflow: TextOverflow.fade, + style: Theme.of(context).textTheme.headlineSmall!.copyWith( + color: Theme.of(context).colorScheme.onSurface, + fontWeight: FontWeight.bold, + ), + ), ), ), ], @@ -37,6 +39,7 @@ class MealWidget extends StatelessWidget { final Meal meal; final ApiClient apiClient; final Function() refreshParent; + final Function(String) showText; final bool initiallyExpanded; const MealWidget({ @@ -45,19 +48,73 @@ class MealWidget extends StatelessWidget { required this.apiClient, required this.refreshParent, required this.initiallyExpanded, + required this.showText, }); - Future _editMeal(context) async { - await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => MealScreen( - apiClient: apiClient, - meal: meal, - refresh: refreshParent, - ), - ), - ).then((_) => refreshParent()); + Future saveMeal(context) async { + TextEditingController textFieldController = TextEditingController(); + textFieldController.text = meal.name; + + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: const Text('Save Meal'), + content: TextField( + controller: textFieldController, + decoration: const InputDecoration(hintText: "Meal template name"), + ), + actions: [ + IconButton( + icon: const Icon(Icons.cancel), + onPressed: () { + Navigator.pop(context); + }, + ), + IconButton( + icon: const Icon(Icons.save), + onPressed: () { + apiClient.saveMeal(meal, textFieldController.text); + Navigator.pop(context); + showText("Meal saved"); + }, + ), + ], + ); + }, + ); + } + + Future _deleteMeal(Meal meal) async { + await apiClient.deleteMeal(meal.id); + } + + Future deleteMeal(context) async { + showDialog( + context: context, + barrierDismissible: false, + builder: (context) { + return AlertDialog( + title: const Text('Confirm deletion of the meal'), + actions: [ + IconButton( + icon: const Icon(Icons.cancel), + onPressed: () { + Navigator.pop(context); + }, + ), + IconButton( + icon: const Icon(Icons.delete), + onPressed: () { + _deleteMeal(meal).then((_) => refreshParent()); + Navigator.pop(context); + showText("Meal deleted"); + }, + ), + ], + ); + }, + ); } Future _editEntry(context, entry) async { @@ -84,61 +141,61 @@ class MealWidget extends StatelessWidget { child: Padding( padding: const EdgeInsets.all(8), child: Card( - elevation: 4, clipBehavior: Clip.antiAlias, - shadowColor: colorScheme.primary.withOpacity(1.0), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(24), ), - child: SizedBox( - width: width, - child: Container( - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - colorScheme.primary.withOpacity(0.6), - colorScheme.secondary.withOpacity(0.5), - ], - ), - ), - child: InkWell( - splashColor: Colors.blue.withAlpha(30), - onLongPress: () => _editMeal(context), - child: ExpansionTile( - iconColor: colorScheme.onPrimary, - collapsedIconColor: colorScheme.onPrimary, - initiallyExpanded: initiallyExpanded, - title: Padding( - padding: const EdgeInsets.all(8), - child: Column( - children: [ - MealHeader(meal: meal), - const MacroHeaderWidget( - calories: true, - ), - MacroEntryWidget( - protein: meal.protein, - carb: meal.carb, - fat: meal.fat, - calories: meal.calories, - ), - ], - ), - ), + child: Container( + constraints: BoxConstraints(maxWidth: width), + color: colorScheme.surface.withOpacity(0.2), + child: ExpansionTile( + iconColor: colorScheme.onSurface, + collapsedIconColor: colorScheme.onSurface, + initiallyExpanded: initiallyExpanded, + enableFeedback: true, + title: Padding( + padding: const EdgeInsets.all(8), + child: Column( children: [ - for (var (i, entry) in meal.entries.indexed) - ListTile( - title: EntryWidget( - entry: entry, - ), - tileColor: i % 2 == 0 - ? colorScheme.secondary.withOpacity(0.1) - : Colors.transparent, - onTap: () => _editEntry(context, entry), - ) + MealHeader(meal: meal), + const MacroHeaderWidget( + calories: true, + ), + MacroEntryWidget( + protein: meal.protein, + carb: meal.carb, + fat: meal.fat, + calories: meal.calories, + ), ], ), ), + children: [ + for (var (i, entry) in meal.entries.indexed) + ListTile( + title: EntryWidget( + entry: entry, + ), + tileColor: i % 2 == 0 + ? colorScheme.surfaceVariant.withOpacity(0.1) + : Colors.transparent, + onTap: () => _editEntry(context, entry), + enableFeedback: true, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + IconButton( + icon: const Icon(Icons.save), + onPressed: () => saveMeal(context), + ), + IconButton( + icon: const Icon(Icons.delete), + onPressed: () => deleteMeal(context), + ), + ], + ), + ], ), ), ), diff --git a/lib/widgets/preset.dart b/lib/widgets/preset.dart index 0f4e0f8..30c9bff 100644 --- a/lib/widgets/preset.dart +++ b/lib/widgets/preset.dart @@ -3,6 +3,33 @@ import 'package:fooder/models/preset.dart'; import 'package:fooder/widgets/macro.dart'; import 'dart:core'; +class PresetHeader extends StatelessWidget { + final String title; + + const PresetHeader({super.key, required this.title}); + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Text( + title, + overflow: TextOverflow.fade, + style: Theme.of(context).textTheme.headlineSmall!.copyWith( + color: Theme.of(context).colorScheme.onSurface, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ); + } +} + class PresetWidget extends StatelessWidget { final Preset preset; @@ -14,24 +41,21 @@ class PresetWidget extends StatelessWidget { padding: const EdgeInsets.all(8), child: Column( children: [ - Row( - children: [ - Expanded( - child: Text( - preset.name, - style: Theme.of(context).textTheme.titleLarge, - ), - ), - Text("${preset.calories.toStringAsFixed(1)} kcal"), - ], + PresetHeader( + title: preset.name, ), - MacroWidget( + const MacroHeaderWidget( + fiber: true, + calories: true, + alignment: Alignment.center, + ), + MacroEntryWidget( protein: preset.protein, carb: preset.carb, fat: preset.fat, - style: Theme.of(context).textTheme.bodyMedium!.copyWith( - color: Theme.of(context).colorScheme.secondary, - ), + fiber: preset.fiber, + calories: preset.calories, + alignment: Alignment.center, ), ], ), diff --git a/lib/widgets/product.dart b/lib/widgets/product.dart index fd3c2f1..eb99d67 100644 --- a/lib/widgets/product.dart +++ b/lib/widgets/product.dart @@ -3,6 +3,33 @@ import 'package:fooder/models/product.dart'; import 'package:fooder/widgets/macro.dart'; import 'dart:core'; +class ProductHeader extends StatelessWidget { + final String title; + + const ProductHeader({super.key, required this.title}); + + @override + Widget build(BuildContext context) { + return Row( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Text( + title, + overflow: TextOverflow.fade, + style: Theme.of(context).textTheme.headlineSmall!.copyWith( + color: Theme.of(context).colorScheme.onSurface, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ); + } +} + class ProductWidget extends StatelessWidget { final Product product; @@ -14,26 +41,21 @@ class ProductWidget extends StatelessWidget { padding: const EdgeInsets.all(8), child: Column( children: [ - Row( - children: [ - Expanded( - child: Text( - product.name, - style: Theme.of(context).textTheme.titleLarge, - ), - ), - Text("${product.calories.toStringAsFixed(1)} kcal"), - ], + ProductHeader( + title: product.name, ), - MacroWidget( + const MacroHeaderWidget( + fiber: true, + calories: true, + alignment: Alignment.center, + ), + MacroEntryWidget( protein: product.protein, carb: product.carb, fat: product.fat, fiber: product.fiber, - style: Theme.of(context).textTheme.bodyMedium!.copyWith( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - ), + calories: product.calories, + alignment: Alignment.center, ), ], ), diff --git a/lib/widgets/summary.dart b/lib/widgets/summary.dart index a0354df..30c53cc 100644 --- a/lib/widgets/summary.dart +++ b/lib/widgets/summary.dart @@ -1,15 +1,13 @@ import 'package:flutter/material.dart'; import 'package:fooder/models/diary.dart'; -import 'package:fooder/widgets/macroEntry.dart'; -import 'package:fooder/screens/add_meal.dart'; +import 'package:fooder/widgets/macro.dart'; import 'package:fooder/client.dart'; import 'dart:core'; class SummaryHeader extends StatelessWidget { final Diary diary; - final Function addMeal; - const SummaryHeader({super.key, required this.addMeal, required this.diary}); + const SummaryHeader({super.key, required this.diary}); @override Widget build(BuildContext context) { @@ -20,21 +18,12 @@ class SummaryHeader extends StatelessWidget { child: Text( "Summary", style: Theme.of(context).textTheme.headlineSmall!.copyWith( - color: Theme.of(context).colorScheme.onPrimary, + color: Theme.of(context).colorScheme.onSurface, fontWeight: FontWeight.bold, ), ), ), const Spacer(), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: IconButton( - icon: const Icon(Icons.playlist_add_rounded), - iconSize: 32, - color: Theme.of(context).colorScheme.onPrimary, - onPressed: () => addMeal(context), - ), - ), ], ); } @@ -53,18 +42,6 @@ class SummaryWidget extends StatelessWidget { required this.apiClient, required this.refreshParent}); - Future _addMeal(context) async { - await Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AddMealScreen( - apiClient: apiClient, - diary: diary, - ), - ), - ).then((_) => refreshParent()); - } - @override Widget build(BuildContext context) { var theme = Theme.of(context); @@ -77,40 +54,28 @@ class SummaryWidget extends StatelessWidget { child: Padding( padding: const EdgeInsets.all(8), child: Card( - elevation: 4, clipBehavior: Clip.antiAlias, - shadowColor: colorScheme.primary.withOpacity(1.0), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(24), ), - child: SizedBox( - width: width, - child: Container( - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - colorScheme.primary.withOpacity(0.6), - colorScheme.secondary.withOpacity(0.5), - ], - ), - ), - child: Padding( - padding: - const EdgeInsets.symmetric(vertical: 12, horizontal: 24), - child: Column( - children: [ - SummaryHeader(diary: diary, addMeal: _addMeal), - const MacroHeaderWidget( - calories: true, - ), - MacroEntryWidget( - protein: diary.protein, - carb: diary.carb, - fat: diary.fat, - calories: diary.calories, - ), - ], - ), + child: Container( + constraints: BoxConstraints(maxWidth: width), + color: colorScheme.surface.withOpacity(0.2), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 24), + child: Column( + children: [ + SummaryHeader(diary: diary), + const MacroHeaderWidget( + calories: true, + ), + MacroEntryWidget( + protein: diary.protein, + carb: diary.carb, + fat: diary.fat, + calories: diary.calories, + ), + ], ), ), ), diff --git a/macos/Podfile.lock b/macos/Podfile.lock new file mode 100644 index 0000000..a0ce364 --- /dev/null +++ b/macos/Podfile.lock @@ -0,0 +1,29 @@ +PODS: + - flutter_secure_storage_macos (6.1.1): + - FlutterMacOS + - FlutterMacOS (1.0.0) + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`) + - FlutterMacOS (from `Flutter/ephemeral`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + +EXTERNAL SOURCES: + flutter_secure_storage_macos: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos + FlutterMacOS: + :path: Flutter/ephemeral + path_provider_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + +SPEC CHECKSUMS: + flutter_secure_storage_macos: d56e2d218c1130b262bef8b4a7d64f88d7f9c9ea + FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 + path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c + +PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367 + +COCOAPODS: 1.15.2 diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 005697a..eed0bf0 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -27,6 +27,8 @@ 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; + 47A87A2D935C9FD21BC18BA6 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 17BEB3BB725731AD7E5B80B1 /* Pods_Runner.framework */; }; + DC768C2964C710CDD24D0DB4 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 465D02A290608CA511C1F4CA /* Pods_RunnerTests.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -60,11 +62,14 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0834B9429B6D5467EDC30594 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 17BEB3BB725731AD7E5B80B1 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 19DEDDAC7F8C48D43A9E76CF /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = ""; }; 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* fooder_web.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "fooder_web.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10ED2044A3C60003C045 /* fooder_web.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = fooder_web.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; @@ -76,8 +81,13 @@ 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 465D02A290608CA511C1F4CA /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; + A4E1FEE05E55FE57D150055B /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + A7C614E4C8DC6AE860A60034 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + D32BEBE6FA5B351434300418 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = ""; }; + F971A3061D014BCFE5A477A9 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -85,6 +95,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + DC768C2964C710CDD24D0DB4 /* Pods_RunnerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -92,12 +103,27 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 47A87A2D935C9FD21BC18BA6 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 076AC79CB527EDDF03C6C1BF /* Pods */ = { + isa = PBXGroup; + children = ( + 0834B9429B6D5467EDC30594 /* Pods-Runner.debug.xcconfig */, + A7C614E4C8DC6AE860A60034 /* Pods-Runner.release.xcconfig */, + A4E1FEE05E55FE57D150055B /* Pods-Runner.profile.xcconfig */, + F971A3061D014BCFE5A477A9 /* Pods-RunnerTests.debug.xcconfig */, + D32BEBE6FA5B351434300418 /* Pods-RunnerTests.release.xcconfig */, + 19DEDDAC7F8C48D43A9E76CF /* Pods-RunnerTests.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; 331C80D6294CF71000263BE5 /* RunnerTests */ = { isa = PBXGroup; children = ( @@ -125,6 +151,7 @@ 331C80D6294CF71000263BE5 /* RunnerTests */, 33CC10EE2044A3C60003C045 /* Products */, D73912EC22F37F3D000D13A0 /* Frameworks */, + 076AC79CB527EDDF03C6C1BF /* Pods */, ); sourceTree = ""; }; @@ -175,6 +202,8 @@ D73912EC22F37F3D000D13A0 /* Frameworks */ = { isa = PBXGroup; children = ( + 17BEB3BB725731AD7E5B80B1 /* Pods_Runner.framework */, + 465D02A290608CA511C1F4CA /* Pods_RunnerTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -186,6 +215,7 @@ isa = PBXNativeTarget; buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildPhases = ( + EBBB44C74E6664565AAD7743 /* [CP] Check Pods Manifest.lock */, 331C80D1294CF70F00263BE5 /* Sources */, 331C80D2294CF70F00263BE5 /* Frameworks */, 331C80D3294CF70F00263BE5 /* Resources */, @@ -204,11 +234,13 @@ isa = PBXNativeTarget; buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + DD4A3E0D06F0EB3D92595679 /* [CP] Check Pods Manifest.lock */, 33CC10E92044A3C60003C045 /* Sources */, 33CC10EA2044A3C60003C045 /* Frameworks */, 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, + 3020AFE6AB38B106E5D2E587 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -227,7 +259,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 331C80D4294CF70F00263BE5 = { @@ -290,6 +322,23 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 3020AFE6AB38B106E5D2E587 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; 3399D490228B24CF009A79C7 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -328,6 +377,50 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; + DD4A3E0D06F0EB3D92595679 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + EBBB44C74E6664565AAD7743 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -379,6 +472,7 @@ /* Begin XCBuildConfiguration section */ 331C80DB294CF71000263BE5 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = F971A3061D014BCFE5A477A9 /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -393,6 +487,7 @@ }; 331C80DC294CF71000263BE5 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = D32BEBE6FA5B351434300418 /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; @@ -407,6 +502,7 @@ }; 331C80DD294CF71000263BE5 /* Profile */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 19DEDDAC7F8C48D43A9E76CF /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CURRENT_PROJECT_VERSION = 1; diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 6b55566..90ab1f4 100644 --- a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ + +