[new look] first draft finished
This commit is contained in:
parent
ac803d3e71
commit
c716de3e02
32 changed files with 856 additions and 987 deletions
48
Dockerfile
48
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"]
|
||||
|
|
1
Makefile
1
Makefile
|
@ -9,6 +9,7 @@ endif
|
|||
|
||||
.PHONY: build
|
||||
build:
|
||||
flutter build web
|
||||
$(DOCKER_BUILD) -t registry.domandoman.xyz/fooder/app -f Dockerfile .
|
||||
|
||||
.PHONY: push
|
||||
|
|
|
@ -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,
|
||||
));
|
||||
|
|
37
lib/components/blur_container.dart
Normal file
37
lib/components/blur_container.dart
Normal file
|
@ -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!,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -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<FDatePickerWidget> {
|
|||
child: IconButton(
|
||||
icon: Icon(
|
||||
Icons.calendar_month,
|
||||
color: colorScheme.onPrimary,
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
size: 20,
|
||||
),
|
||||
onPressed: () {
|
||||
|
|
43
lib/components/dropdown.dart
Normal file
43
lib/components/dropdown.dart
Normal file
|
@ -0,0 +1,43 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class FDropdown<T> extends StatelessWidget {
|
||||
final String labelText;
|
||||
final List<DropdownMenuItem<T>> 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<T>(
|
||||
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),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
49
lib/components/floating_action_button.dart
Normal file
49
lib/components/floating_action_button.dart
Normal file
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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<Widget> 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,
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
),
|
||||
]),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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<Path> {
|
|||
}
|
||||
|
||||
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) =>
|
||||
|
|
|
@ -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<TextInputFormatter>? 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,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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<AddEntryScreen> {
|
|||
constraints: const BoxConstraints(maxWidth: 720),
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: ListView(children: <Widget>[
|
||||
DropdownButton<Meal>(
|
||||
FDropdown<Meal>(
|
||||
labelText: 'Meal',
|
||||
value: meal,
|
||||
// Callback that sets the selected popup menu item.
|
||||
onChanged: (Meal? meal) {
|
||||
|
@ -151,19 +155,15 @@ class _AddEntryScreen extends BasedState<AddEntryScreen> {
|
|||
),
|
||||
],
|
||||
),
|
||||
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: <TextInputFormatter>[
|
||||
|
@ -212,14 +212,15 @@ class _AddEntryScreen extends BasedState<AddEntryScreen> {
|
|||
floatingActionButton: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: <Widget>[
|
||||
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",
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -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<AddMealScreen> createState() => _AddMealScreen();
|
||||
}
|
||||
|
||||
class _AddMealScreen extends State<AddMealScreen> {
|
||||
class _AddMealScreen extends BasedState<AddMealScreen> {
|
||||
final nameController = TextEditingController();
|
||||
final presetNameController = TextEditingController();
|
||||
bool nameChanged = false;
|
||||
|
@ -37,7 +39,7 @@ class _AddMealScreen extends State<AddMealScreen> {
|
|||
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<AddMealScreen> {
|
|||
);
|
||||
}
|
||||
|
||||
void showError(String message) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(message, textAlign: TextAlign.center),
|
||||
backgroundColor: Theme.of(context).colorScheme.error,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _addMeal() async {
|
||||
await widget.apiClient.addMeal(
|
||||
name: nameController.text,
|
||||
|
@ -121,28 +114,21 @@ class _AddMealScreen extends State<AddMealScreen> {
|
|||
@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: <Widget>[
|
||||
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<AddMealScreen> {
|
|||
]),
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
floatingActionButton: FActionButton(
|
||||
onPressed: _addMealFromPreset,
|
||||
child: const Icon(Icons.add),
|
||||
icon: Icons.playlist_add_rounded,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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<AddProductScreen> createState() => _AddProductScreen();
|
||||
}
|
||||
|
||||
class _AddProductScreen extends State<AddProductScreen> {
|
||||
class _AddProductScreen extends BasedState<AddProductScreen> {
|
||||
final nameController = TextEditingController();
|
||||
final carbController = TextEditingController();
|
||||
final fatController = TextEditingController();
|
||||
|
@ -34,15 +37,6 @@ class _AddProductScreen extends State<AddProductScreen> {
|
|||
);
|
||||
}
|
||||
|
||||
void showError(String message) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(message, textAlign: TextAlign.center),
|
||||
backgroundColor: Theme.of(context).colorScheme.error,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<double?> _parseDouble(String text, String name,
|
||||
{bool silent = false}) async {
|
||||
try {
|
||||
|
@ -113,25 +107,21 @@ class _AddProductScreen extends State<AddProductScreen> {
|
|||
@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: <Widget>[
|
||||
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: <TextInputFormatter>[
|
||||
|
@ -143,10 +133,8 @@ class _AddProductScreen extends State<AddProductScreen> {
|
|||
setState(() {});
|
||||
},
|
||||
),
|
||||
TextFormField(
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Fat',
|
||||
),
|
||||
FTextInput(
|
||||
labelText: 'Fat',
|
||||
keyboardType:
|
||||
const TextInputType.numberWithOptions(decimal: true),
|
||||
inputFormatters: <TextInputFormatter>[
|
||||
|
@ -158,10 +146,8 @@ class _AddProductScreen extends State<AddProductScreen> {
|
|||
setState(() {});
|
||||
},
|
||||
),
|
||||
TextFormField(
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Protein',
|
||||
),
|
||||
FTextInput(
|
||||
labelText: 'Protein',
|
||||
keyboardType:
|
||||
const TextInputType.numberWithOptions(decimal: true),
|
||||
inputFormatters: <TextInputFormatter>[
|
||||
|
@ -173,10 +159,8 @@ class _AddProductScreen extends State<AddProductScreen> {
|
|||
setState(() {});
|
||||
},
|
||||
),
|
||||
TextFormField(
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Fiber',
|
||||
),
|
||||
FTextInput(
|
||||
labelText: 'Fiber',
|
||||
keyboardType:
|
||||
const TextInputType.numberWithOptions(decimal: true),
|
||||
inputFormatters: <TextInputFormatter>[
|
||||
|
@ -188,15 +172,30 @@ class _AddProductScreen extends State<AddProductScreen> {
|
|||
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,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ abstract class BasedState<T extends BasedScreen> extends State<T> {
|
|||
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<T extends BasedScreen> extends State<T> {
|
|||
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: () {},
|
||||
),
|
||||
|
|
|
@ -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<EditEntryScreen> createState() => _EditEntryScreen();
|
||||
}
|
||||
|
||||
class _EditEntryScreen extends State<EditEntryScreen> {
|
||||
class _EditEntryScreen extends BasedState<EditEntryScreen> {
|
||||
final gramsController = TextEditingController();
|
||||
final productNameController = TextEditingController();
|
||||
List<Product> products = [];
|
||||
|
@ -53,15 +55,6 @@ class _EditEntryScreen extends State<EditEntryScreen> {
|
|||
});
|
||||
}
|
||||
|
||||
void showError(String message) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(message, textAlign: TextAlign.center),
|
||||
backgroundColor: Theme.of(context).colorScheme.error,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<double?> _parseDouble(String text, String name) async {
|
||||
try {
|
||||
return double.parse(text.replaceAll(",", "."));
|
||||
|
@ -123,27 +116,20 @@ class _EditEntryScreen extends State<EditEntryScreen> {
|
|||
@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: <Widget>[
|
||||
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: <TextInputFormatter>[
|
||||
|
@ -190,20 +176,21 @@ class _EditEntryScreen extends State<EditEntryScreen> {
|
|||
floatingActionButton: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: <Widget>[
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -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<MainScreen> {
|
|||
}
|
||||
|
||||
Future<void> _addEntry() async {
|
||||
if (diary == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
|
@ -52,60 +57,20 @@ class _MainScreen extends BasedState<MainScreen> {
|
|||
).then((_) => _asyncInitState());
|
||||
}
|
||||
|
||||
Widget floatingActionButton(BuildContext context) {
|
||||
var theme = Theme.of(context);
|
||||
var colorScheme = theme.colorScheme;
|
||||
Future<void> _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<MainScreen> {
|
|||
apiClient: widget.apiClient,
|
||||
refreshParent: _asyncInitState,
|
||||
initiallyExpanded: i == 0,
|
||||
showText: showText,
|
||||
),
|
||||
const SizedBox(height: 200),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -149,7 +116,18 @@ class _MainScreen extends BasedState<MainScreen> {
|
|||
appBar: appBar(),
|
||||
bottomNavigationBar: navBar(),
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
|
||||
floatingActionButton: floatingActionButton(context),
|
||||
floatingActionButton: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: <Widget>[
|
||||
FActionButton(
|
||||
icon: Icons.playlist_add,
|
||||
onPressed: () => _addMeal(context),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
FActionButton(
|
||||
icon: Icons.library_add, onPressed: _addEntry, tag: "fap2"),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<MealScreen> createState() => _AddMealScreen();
|
||||
}
|
||||
|
||||
class _AddMealScreen extends State<MealScreen> {
|
||||
Future<void> 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: <Widget>[
|
||||
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<void> _deleteMeal(Meal meal) async {
|
||||
await widget.apiClient.deleteMeal(meal.id);
|
||||
}
|
||||
|
||||
Future<void> deleteMeal(context) async {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: const Text('Confirm deletion of the meal'),
|
||||
actions: <Widget>[
|
||||
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: <Widget>[
|
||||
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: <Widget>[
|
||||
SliverAppBar(
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
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),
|
||||
),
|
||||
]))
|
||||
]),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
51
lib/theme.dart
Normal file
51
lib/theme.dart
Normal file
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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: <Widget>[
|
||||
SliverAppBar(
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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: <Widget>[
|
||||
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,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -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 = <Widget>[
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Text(
|
||||
"C: ${carb.toStringAsFixed(1)}g",
|
||||
style: style,
|
||||
textAlign: TextAlign.center,
|
||||
var elements = <String>[
|
||||
"C(g)",
|
||||
"F(g)",
|
||||
"P(g)",
|
||||
];
|
||||
|
||||
if (fiber == true) {
|
||||
elements.add(
|
||||
"f(g)",
|
||||
);
|
||||
}
|
||||
|
||||
if (calories == true) {
|
||||
elements.add(
|
||||
"kcal",
|
||||
);
|
||||
}
|
||||
|
||||
var children = <Widget>[];
|
||||
|
||||
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 = <String>[
|
||||
(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 = <Widget>[];
|
||||
|
||||
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,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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 = <String>[
|
||||
"C(g)",
|
||||
"F(g)",
|
||||
"P(g)",
|
||||
];
|
||||
|
||||
if (fiber == true) {
|
||||
elements.add(
|
||||
"F(g)",
|
||||
);
|
||||
}
|
||||
|
||||
if (calories == true) {
|
||||
elements.add(
|
||||
"kcal",
|
||||
);
|
||||
}
|
||||
|
||||
var children = <Widget>[];
|
||||
|
||||
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 = <String>[
|
||||
(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 = <Widget>[];
|
||||
|
||||
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,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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: <Widget>[
|
||||
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<void> _editMeal(context) async {
|
||||
await Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => MealScreen(
|
||||
apiClient: apiClient,
|
||||
meal: meal,
|
||||
refresh: refreshParent,
|
||||
),
|
||||
),
|
||||
).then((_) => refreshParent());
|
||||
Future<void> 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: <Widget>[
|
||||
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<void> _deleteMeal(Meal meal) async {
|
||||
await apiClient.deleteMeal(meal.id);
|
||||
}
|
||||
|
||||
Future<void> deleteMeal(context) async {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: const Text('Confirm deletion of the meal'),
|
||||
actions: <Widget>[
|
||||
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<void> _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: <Widget>[
|
||||
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: <Widget>[
|
||||
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: <Widget>[
|
||||
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: <Widget>[
|
||||
IconButton(
|
||||
icon: const Icon(Icons.save),
|
||||
onPressed: () => saveMeal(context),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.delete),
|
||||
onPressed: () => deleteMeal(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -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: <Widget>[
|
||||
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: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -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: <Widget>[
|
||||
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: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -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<void> _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: <Widget>[
|
||||
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: <Widget>[
|
||||
SummaryHeader(diary: diary),
|
||||
const MacroHeaderWidget(
|
||||
calories: true,
|
||||
),
|
||||
MacroEntryWidget(
|
||||
protein: diary.protein,
|
||||
carb: diary.carb,
|
||||
fat: diary.fat,
|
||||
calories: diary.calories,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
29
macos/Podfile.lock
Normal file
29
macos/Podfile.lock
Normal file
|
@ -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
|
|
@ -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 = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
|
||||
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
|
||||
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||
|
@ -76,8 +81,13 @@
|
|||
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
|
||||
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
|
||||
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
/* 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 = "<group>";
|
||||
};
|
||||
331C80D6294CF71000263BE5 /* RunnerTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -125,6 +151,7 @@
|
|||
331C80D6294CF71000263BE5 /* RunnerTests */,
|
||||
33CC10EE2044A3C60003C045 /* Products */,
|
||||
D73912EC22F37F3D000D13A0 /* Frameworks */,
|
||||
076AC79CB527EDDF03C6C1BF /* Pods */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
|
@ -175,6 +202,8 @@
|
|||
D73912EC22F37F3D000D13A0 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
17BEB3BB725731AD7E5B80B1 /* Pods_Runner.framework */,
|
||||
465D02A290608CA511C1F4CA /* Pods_RunnerTests.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
|
@ -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;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1430"
|
||||
LastUpgradeVersion = "1510"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
|
|
@ -4,4 +4,7 @@
|
|||
<FileRef
|
||||
location = "group:Runner.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
|
Loading…
Reference in a new issue