[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
|
COPY ./build/web /app
|
||||||
RUN apt-get update
|
|
||||||
RUN apt-get install -y curl git unzip
|
|
||||||
|
|
||||||
# define variables
|
WORKDIR /app/
|
||||||
ARG FLUTTER_SDK=/usr/local/flutter
|
|
||||||
ARG FLUTTER_VERSION=3.10.5
|
|
||||||
ARG APP=/app/
|
|
||||||
|
|
||||||
#clone flutter
|
RUN apk --no-cache add curl
|
||||||
RUN git clone https://github.com/flutter/flutter.git $FLUTTER_SDK
|
RUN npm install --global http-server
|
||||||
# change dir to current flutter folder and make a checkout to the specific version
|
|
||||||
|
|
||||||
# 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
|
EXPOSE 80
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
|
||||||
|
CMD ["npx", "http-server", "-p", "80"]
|
||||||
|
|
1
Makefile
1
Makefile
|
@ -9,6 +9,7 @@ endif
|
||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
build:
|
build:
|
||||||
|
flutter build web
|
||||||
$(DOCKER_BUILD) -t registry.domandoman.xyz/fooder/app -f Dockerfile .
|
$(DOCKER_BUILD) -t registry.domandoman.xyz/fooder/app -f Dockerfile .
|
||||||
|
|
||||||
.PHONY: push
|
.PHONY: push
|
||||||
|
|
|
@ -11,6 +11,8 @@ class FAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
child: AppBar(
|
child: AppBar(
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
|
shadowColor: Colors.transparent,
|
||||||
|
surfaceTintColor: Colors.transparent,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
actions: actions,
|
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(
|
child: Container(
|
||||||
padding: EdgeInsets.symmetric(vertical: insidePadding),
|
padding: EdgeInsets.symmetric(vertical: insidePadding),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: LinearGradient(
|
|
||||||
colors: [
|
|
||||||
colorScheme.primary.withOpacity(0.5),
|
|
||||||
colorScheme.secondary.withOpacity(0.5),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.circular(4),
|
borderRadius: BorderRadius.circular(4),
|
||||||
boxShadow: [
|
color: colorScheme.surfaceTint.withOpacity(0.85),
|
||||||
BoxShadow(
|
|
||||||
color: colorScheme.primary.withOpacity(0.3),
|
|
||||||
blurRadius: 5,
|
|
||||||
offset: const Offset(0, 5),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
|
@ -48,6 +36,7 @@ class FButton extends StatelessWidget {
|
||||||
style: theme.textTheme.labelLarge!.copyWith(
|
style: theme.textTheme.labelLarge!.copyWith(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: fontSize,
|
fontSize: fontSize,
|
||||||
|
color: colorScheme.onPrimary,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -40,7 +40,7 @@ class FDateItemWidget extends StatelessWidget {
|
||||||
width: 2,
|
width: 2,
|
||||||
),
|
),
|
||||||
color: picked
|
color: picked
|
||||||
? colorScheme.onPrimary.withOpacity(0.25)
|
? colorScheme.onSurfaceVariant.withOpacity(0.25)
|
||||||
: Colors.transparent,
|
: Colors.transparent,
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
@ -49,7 +49,7 @@ class FDateItemWidget extends StatelessWidget {
|
||||||
Text(
|
Text(
|
||||||
dayOfTheWeekMap[date.weekday]!,
|
dayOfTheWeekMap[date.weekday]!,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: colorScheme.onPrimary,
|
color: colorScheme.onSurfaceVariant,
|
||||||
fontSize: picked ? 24 : 12,
|
fontSize: picked ? 24 : 12,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
|
@ -57,7 +57,7 @@ class FDateItemWidget extends StatelessWidget {
|
||||||
Text(
|
Text(
|
||||||
'${date.day}.${date.month}',
|
'${date.day}.${date.month}',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: colorScheme.onPrimary,
|
color: colorScheme.onSurfaceVariant,
|
||||||
fontSize: picked ? 24 : 12,
|
fontSize: picked ? 24 : 12,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
|
@ -128,7 +128,7 @@ class _FDatePickerWidgetState extends State<FDatePickerWidget> {
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.calendar_month,
|
Icons.calendar_month,
|
||||||
color: colorScheme.onPrimary,
|
color: colorScheme.onSurfaceVariant,
|
||||||
size: 20,
|
size: 20,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
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:flutter/material.dart';
|
||||||
import 'package:blur/blur.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:fooder/components/blur_container.dart';
|
||||||
|
|
||||||
class FNavBar extends StatelessWidget {
|
class FNavBar extends StatelessWidget {
|
||||||
static const maxWidth = 920.0;
|
static const maxWidth = 920.0;
|
||||||
|
@ -7,61 +8,25 @@ class FNavBar extends StatelessWidget {
|
||||||
final List<Widget> children;
|
final List<Widget> children;
|
||||||
final double height;
|
final double height;
|
||||||
|
|
||||||
const FNavBar({super.key, required this.children, this.height = 56});
|
const FNavBar({super.key, required this.children, this.height = 78});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var theme = Theme.of(context);
|
|
||||||
var colorScheme = theme.colorScheme;
|
|
||||||
|
|
||||||
var widthAvail = MediaQuery.of(context).size.width;
|
var widthAvail = MediaQuery.of(context).size.width;
|
||||||
// var width = widthAvail > maxWidth ? maxWidth : widthAvail;
|
// var width = widthAvail > maxWidth ? maxWidth : widthAvail;
|
||||||
|
return SizedBox(
|
||||||
return SafeArea(
|
width: widthAvail,
|
||||||
child: Padding(
|
height: height * children.length,
|
||||||
padding: const EdgeInsets.all(12),
|
child: BlurContainer(
|
||||||
child: Container(
|
width: widthAvail,
|
||||||
decoration: BoxDecoration(
|
height: height * children.length,
|
||||||
borderRadius: BorderRadius.circular(24),
|
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||||
boxShadow: [
|
...children,
|
||||||
BoxShadow(
|
Container(
|
||||||
color: colorScheme.primary.withOpacity(0.3),
|
height: height / 3,
|
||||||
blurRadius: 5,
|
color: Colors.transparent,
|
||||||
offset: const Offset(0, 5),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
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:flutter/material.dart';
|
||||||
import 'package:blur/blur.dart';
|
import 'package:fooder/components/blur_container.dart';
|
||||||
|
|
||||||
class ClipShadowPath extends StatelessWidget {
|
class ClipShadowPath extends StatelessWidget {
|
||||||
final Shadow shadow;
|
final Shadow shadow;
|
||||||
|
@ -56,28 +56,11 @@ class BackgroundWave extends StatelessWidget {
|
||||||
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: height,
|
height: height,
|
||||||
child: ClipShadowPath(
|
child: ClipPath(
|
||||||
clipper: BackgroundWaveClipper(),
|
clipper: BackgroundWaveClipper(),
|
||||||
shadow: BoxShadow(
|
child: BlurContainer(
|
||||||
blurRadius: 5,
|
width: MediaQuery.of(context).size.width,
|
||||||
color: colorScheme.primary.withOpacity(0.3),
|
height: height,
|
||||||
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),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -131,8 +114,9 @@ class BackgroundWaveClipper extends CustomClipper<Path> {
|
||||||
}
|
}
|
||||||
|
|
||||||
class FSliverAppBar extends SliverPersistentHeaderDelegate {
|
class FSliverAppBar extends SliverPersistentHeaderDelegate {
|
||||||
|
final double preferredHeight;
|
||||||
final Widget child;
|
final Widget child;
|
||||||
const FSliverAppBar({required this.child});
|
const FSliverAppBar({required this.child, this.preferredHeight = 220});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(
|
Widget build(
|
||||||
|
@ -147,8 +131,11 @@ class FSliverAppBar extends SliverPersistentHeaderDelegate {
|
||||||
|
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
const BackgroundWave(
|
// const BackgroundWave(
|
||||||
height: 280,
|
// height: preferredHeight,
|
||||||
|
// ),
|
||||||
|
BlurContainer(
|
||||||
|
height: preferredHeight,
|
||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
top: offset,
|
top: offset,
|
||||||
|
@ -161,10 +148,10 @@ class FSliverAppBar extends SliverPersistentHeaderDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
double get maxExtent => 280;
|
double get maxExtent => preferredHeight;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
double get minExtent => 140;
|
double get minExtent => preferredHeight / 2;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) =>
|
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) =>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
class FTextInput extends StatelessWidget {
|
class FTextInput extends StatelessWidget {
|
||||||
final String labelText;
|
final String labelText;
|
||||||
|
@ -8,6 +9,9 @@ class FTextInput extends StatelessWidget {
|
||||||
final bool autofocus;
|
final bool autofocus;
|
||||||
final bool obscureText;
|
final bool obscureText;
|
||||||
final Function(String)? onFieldSubmitted;
|
final Function(String)? onFieldSubmitted;
|
||||||
|
final TextInputType? keyboardType;
|
||||||
|
final List<TextInputFormatter>? inputFormatters;
|
||||||
|
final Function(String)? onChanged;
|
||||||
|
|
||||||
const FTextInput(
|
const FTextInput(
|
||||||
{super.key,
|
{super.key,
|
||||||
|
@ -17,7 +21,10 @@ class FTextInput extends StatelessWidget {
|
||||||
this.autofillHints,
|
this.autofillHints,
|
||||||
this.autofocus = false,
|
this.autofocus = false,
|
||||||
this.onFieldSubmitted,
|
this.onFieldSubmitted,
|
||||||
this.obscureText = false});
|
this.obscureText = false,
|
||||||
|
this.keyboardType,
|
||||||
|
this.inputFormatters,
|
||||||
|
this.onChanged});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -30,6 +37,8 @@ class FTextInput extends StatelessWidget {
|
||||||
obscureText: obscureText,
|
obscureText: obscureText,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: labelText,
|
labelText: labelText,
|
||||||
|
floatingLabelStyle:
|
||||||
|
theme.textTheme.bodyLarge!.copyWith(color: colorScheme.onSurface),
|
||||||
enabledBorder: OutlineInputBorder(
|
enabledBorder: OutlineInputBorder(
|
||||||
borderSide: BorderSide(color: colorScheme.primary),
|
borderSide: BorderSide(color: colorScheme.primary),
|
||||||
),
|
),
|
||||||
|
@ -41,6 +50,9 @@ class FTextInput extends StatelessWidget {
|
||||||
autofillHints: autofillHints,
|
autofillHints: autofillHints,
|
||||||
autofocus: autofocus,
|
autofocus: autofocus,
|
||||||
onFieldSubmitted: onFieldSubmitted,
|
onFieldSubmitted: onFieldSubmitted,
|
||||||
|
keyboardType: keyboardType,
|
||||||
|
inputFormatters: inputFormatters,
|
||||||
|
onChanged: onChanged,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:fooder/screens/login.dart';
|
import 'package:fooder/screens/login.dart';
|
||||||
import 'package:fooder/client.dart';
|
import 'package:fooder/client.dart';
|
||||||
import 'package:flex_color_scheme/flex_color_scheme.dart';
|
import 'package:fooder/theme.dart';
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
const MyApp({super.key});
|
const MyApp({super.key});
|
||||||
|
@ -10,8 +10,8 @@ class MyApp extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
title: 'FOODER',
|
title: 'FOODER',
|
||||||
theme: FlexThemeData.light(scheme: FlexScheme.brandBlue),
|
theme: MainTheme.light(),
|
||||||
darkTheme: FlexThemeData.dark(scheme: FlexScheme.brandBlue),
|
darkTheme: MainTheme.dark(),
|
||||||
themeMode: ThemeMode.system,
|
themeMode: ThemeMode.system,
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
home: LoginScreen(
|
home: LoginScreen(
|
||||||
|
|
|
@ -5,6 +5,9 @@ import 'package:fooder/models/product.dart';
|
||||||
import 'package:fooder/models/diary.dart';
|
import 'package:fooder/models/diary.dart';
|
||||||
import 'package:fooder/models/meal.dart';
|
import 'package:fooder/models/meal.dart';
|
||||||
import 'package:fooder/widgets/product.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:fooder/screens/add_product.dart';
|
||||||
import 'package:simple_barcode_scanner/simple_barcode_scanner.dart';
|
import 'package:simple_barcode_scanner/simple_barcode_scanner.dart';
|
||||||
|
|
||||||
|
@ -132,7 +135,8 @@ class _AddEntryScreen extends BasedState<AddEntryScreen> {
|
||||||
constraints: const BoxConstraints(maxWidth: 720),
|
constraints: const BoxConstraints(maxWidth: 720),
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
child: ListView(children: <Widget>[
|
child: ListView(children: <Widget>[
|
||||||
DropdownButton<Meal>(
|
FDropdown<Meal>(
|
||||||
|
labelText: 'Meal',
|
||||||
value: meal,
|
value: meal,
|
||||||
// Callback that sets the selected popup menu item.
|
// Callback that sets the selected popup menu item.
|
||||||
onChanged: (Meal? meal) {
|
onChanged: (Meal? meal) {
|
||||||
|
@ -151,19 +155,15 @@ class _AddEntryScreen extends BasedState<AddEntryScreen> {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
TextFormField(
|
FTextInput(
|
||||||
decoration: const InputDecoration(
|
labelText: 'Product name',
|
||||||
labelText: 'Product name',
|
|
||||||
),
|
|
||||||
controller: productNameController,
|
controller: productNameController,
|
||||||
onChanged: (_) => _getProducts(),
|
onChanged: (_) => _getProducts(),
|
||||||
onFieldSubmitted: (_) => _addEntry(),
|
onFieldSubmitted: (_) => _addEntry(),
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
),
|
),
|
||||||
TextFormField(
|
FTextInput(
|
||||||
decoration: const InputDecoration(
|
labelText: 'Grams',
|
||||||
labelText: 'Grams',
|
|
||||||
),
|
|
||||||
keyboardType:
|
keyboardType:
|
||||||
const TextInputType.numberWithOptions(decimal: true),
|
const TextInputType.numberWithOptions(decimal: true),
|
||||||
inputFormatters: <TextInputFormatter>[
|
inputFormatters: <TextInputFormatter>[
|
||||||
|
@ -212,14 +212,15 @@ class _AddEntryScreen extends BasedState<AddEntryScreen> {
|
||||||
floatingActionButton: Row(
|
floatingActionButton: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
FloatingActionButton(
|
FActionButton(
|
||||||
onPressed: _findProductByBarCode,
|
onPressed: _findProductByBarCode,
|
||||||
heroTag: null,
|
icon: Icons.photo_camera,
|
||||||
child: const Icon(Icons.photo_camera),
|
|
||||||
),
|
),
|
||||||
FloatingActionButton(
|
const SizedBox(width: 10),
|
||||||
|
FActionButton(
|
||||||
onPressed: _addEntry,
|
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/diary.dart';
|
||||||
import 'package:fooder/models/preset.dart';
|
import 'package:fooder/models/preset.dart';
|
||||||
import 'package:fooder/widgets/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 {
|
class AddMealScreen extends BasedScreen {
|
||||||
final Diary diary;
|
final Diary diary;
|
||||||
|
@ -14,7 +16,7 @@ class AddMealScreen extends BasedScreen {
|
||||||
State<AddMealScreen> createState() => _AddMealScreen();
|
State<AddMealScreen> createState() => _AddMealScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AddMealScreen extends State<AddMealScreen> {
|
class _AddMealScreen extends BasedState<AddMealScreen> {
|
||||||
final nameController = TextEditingController();
|
final nameController = TextEditingController();
|
||||||
final presetNameController = TextEditingController();
|
final presetNameController = TextEditingController();
|
||||||
bool nameChanged = false;
|
bool nameChanged = false;
|
||||||
|
@ -37,7 +39,7 @@ class _AddMealScreen extends State<AddMealScreen> {
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
setState(() {
|
setState(() {
|
||||||
nameController.text = "Meal ${widget.diary.meals.length}";
|
nameController.text = "Meal ${widget.diary.meals.length + 1}";
|
||||||
});
|
});
|
||||||
_getPresets();
|
_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 {
|
Future<void> _addMeal() async {
|
||||||
await widget.apiClient.addMeal(
|
await widget.apiClient.addMeal(
|
||||||
name: nameController.text,
|
name: nameController.text,
|
||||||
|
@ -121,28 +114,21 @@ class _AddMealScreen extends State<AddMealScreen> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: appBar(),
|
||||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
|
||||||
title: Text("🅵🅾🅾🅳🅴🆁", style: logoStyle(context)),
|
|
||||||
),
|
|
||||||
body: Center(
|
body: Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
constraints: const BoxConstraints(maxWidth: 720),
|
constraints: const BoxConstraints(maxWidth: 720),
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
child: ListView(children: <Widget>[
|
child: ListView(children: <Widget>[
|
||||||
TextFormField(
|
FTextInput(
|
||||||
decoration: const InputDecoration(
|
labelText: 'Meal name',
|
||||||
labelText: 'Meal name',
|
|
||||||
),
|
|
||||||
controller: nameController,
|
controller: nameController,
|
||||||
onChanged: (_) => setState(() {
|
onChanged: (_) => setState(() {
|
||||||
nameChanged = true;
|
nameChanged = true;
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
TextFormField(
|
FTextInput(
|
||||||
decoration: const InputDecoration(
|
labelText: 'Search presets',
|
||||||
hintText: 'Search presets',
|
|
||||||
),
|
|
||||||
controller: presetNameController,
|
controller: presetNameController,
|
||||||
onChanged: (_) => _getPresets(),
|
onChanged: (_) => _getPresets(),
|
||||||
),
|
),
|
||||||
|
@ -166,9 +152,9 @@ class _AddMealScreen extends State<AddMealScreen> {
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FActionButton(
|
||||||
onPressed: _addMealFromPreset,
|
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:flutter/services.dart';
|
||||||
import 'package:fooder/screens/based.dart';
|
import 'package:fooder/screens/based.dart';
|
||||||
import 'package:fooder/models/product.dart';
|
import 'package:fooder/models/product.dart';
|
||||||
|
import 'package:fooder/widgets/product.dart';
|
||||||
|
import 'package:fooder/components/text.dart';
|
||||||
|
import 'package:fooder/components/floating_action_button.dart';
|
||||||
|
|
||||||
class AddProductScreen extends BasedScreen {
|
class AddProductScreen extends BasedScreen {
|
||||||
const AddProductScreen({super.key, required super.apiClient});
|
const AddProductScreen({super.key, required super.apiClient});
|
||||||
|
@ -10,7 +13,7 @@ class AddProductScreen extends BasedScreen {
|
||||||
State<AddProductScreen> createState() => _AddProductScreen();
|
State<AddProductScreen> createState() => _AddProductScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AddProductScreen extends State<AddProductScreen> {
|
class _AddProductScreen extends BasedState<AddProductScreen> {
|
||||||
final nameController = TextEditingController();
|
final nameController = TextEditingController();
|
||||||
final carbController = TextEditingController();
|
final carbController = TextEditingController();
|
||||||
final fatController = 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,
|
Future<double?> _parseDouble(String text, String name,
|
||||||
{bool silent = false}) async {
|
{bool silent = false}) async {
|
||||||
try {
|
try {
|
||||||
|
@ -113,25 +107,21 @@ class _AddProductScreen extends State<AddProductScreen> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: appBar(),
|
||||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
|
||||||
title: Text("🅵🅾🅾🅳🅴🆁", style: logoStyle(context)),
|
|
||||||
),
|
|
||||||
body: Center(
|
body: Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
constraints: const BoxConstraints(maxWidth: 720),
|
constraints: const BoxConstraints(maxWidth: 720),
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
child: Column(children: <Widget>[
|
child: Column(children: <Widget>[
|
||||||
TextFormField(
|
FTextInput(
|
||||||
decoration: const InputDecoration(
|
labelText: 'Product name',
|
||||||
labelText: 'Product name',
|
|
||||||
),
|
|
||||||
controller: nameController,
|
controller: nameController,
|
||||||
|
onChanged: (String value) {
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
),
|
),
|
||||||
TextFormField(
|
FTextInput(
|
||||||
decoration: const InputDecoration(
|
labelText: 'Carbs',
|
||||||
labelText: 'Carbs',
|
|
||||||
),
|
|
||||||
keyboardType:
|
keyboardType:
|
||||||
const TextInputType.numberWithOptions(decimal: true),
|
const TextInputType.numberWithOptions(decimal: true),
|
||||||
inputFormatters: <TextInputFormatter>[
|
inputFormatters: <TextInputFormatter>[
|
||||||
|
@ -143,10 +133,8 @@ class _AddProductScreen extends State<AddProductScreen> {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
TextFormField(
|
FTextInput(
|
||||||
decoration: const InputDecoration(
|
labelText: 'Fat',
|
||||||
labelText: 'Fat',
|
|
||||||
),
|
|
||||||
keyboardType:
|
keyboardType:
|
||||||
const TextInputType.numberWithOptions(decimal: true),
|
const TextInputType.numberWithOptions(decimal: true),
|
||||||
inputFormatters: <TextInputFormatter>[
|
inputFormatters: <TextInputFormatter>[
|
||||||
|
@ -158,10 +146,8 @@ class _AddProductScreen extends State<AddProductScreen> {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
TextFormField(
|
FTextInput(
|
||||||
decoration: const InputDecoration(
|
labelText: 'Protein',
|
||||||
labelText: 'Protein',
|
|
||||||
),
|
|
||||||
keyboardType:
|
keyboardType:
|
||||||
const TextInputType.numberWithOptions(decimal: true),
|
const TextInputType.numberWithOptions(decimal: true),
|
||||||
inputFormatters: <TextInputFormatter>[
|
inputFormatters: <TextInputFormatter>[
|
||||||
|
@ -173,10 +159,8 @@ class _AddProductScreen extends State<AddProductScreen> {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
TextFormField(
|
FTextInput(
|
||||||
decoration: const InputDecoration(
|
labelText: 'Fiber',
|
||||||
labelText: 'Fiber',
|
|
||||||
),
|
|
||||||
keyboardType:
|
keyboardType:
|
||||||
const TextInputType.numberWithOptions(decimal: true),
|
const TextInputType.numberWithOptions(decimal: true),
|
||||||
inputFormatters: <TextInputFormatter>[
|
inputFormatters: <TextInputFormatter>[
|
||||||
|
@ -188,15 +172,30 @@ class _AddProductScreen extends State<AddProductScreen> {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Text(
|
ProductWidget(
|
||||||
"${calculateCalories().toStringAsFixed(2)} kcal",
|
product: Product(
|
||||||
textAlign: TextAlign.right,
|
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,
|
onPressed: _addProduct,
|
||||||
child: const Icon(Icons.add),
|
icon: Icons.save,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ abstract class BasedState<T extends BasedScreen> extends State<T> {
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.logout,
|
Icons.logout,
|
||||||
color: Theme.of(context).colorScheme.onPrimary,
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
onPressed: _logout,
|
onPressed: _logout,
|
||||||
),
|
),
|
||||||
|
@ -60,28 +60,28 @@ abstract class BasedState<T extends BasedScreen> extends State<T> {
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.menu_book,
|
Icons.menu_book,
|
||||||
color: Theme.of(context).colorScheme.onPrimary,
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
onPressed: backToDiary,
|
onPressed: backToDiary,
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.dinner_dining,
|
Icons.dinner_dining,
|
||||||
color: Theme.of(context).colorScheme.onPrimary,
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
onPressed: () {},
|
onPressed: () {},
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.lunch_dining,
|
Icons.lunch_dining,
|
||||||
color: Theme.of(context).colorScheme.onPrimary,
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
onPressed: () {},
|
onPressed: () {},
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.person,
|
Icons.person,
|
||||||
color: Theme.of(context).colorScheme.onPrimary,
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
onPressed: () {},
|
onPressed: () {},
|
||||||
),
|
),
|
||||||
|
|
|
@ -5,6 +5,8 @@ import 'package:fooder/models/product.dart';
|
||||||
import 'package:fooder/models/entry.dart';
|
import 'package:fooder/models/entry.dart';
|
||||||
import 'package:fooder/widgets/product.dart';
|
import 'package:fooder/widgets/product.dart';
|
||||||
import 'package:fooder/screens/add_product.dart';
|
import 'package:fooder/screens/add_product.dart';
|
||||||
|
import 'package:fooder/components/text.dart';
|
||||||
|
import 'package:fooder/components/floating_action_button.dart';
|
||||||
import 'package:simple_barcode_scanner/simple_barcode_scanner.dart';
|
import 'package:simple_barcode_scanner/simple_barcode_scanner.dart';
|
||||||
|
|
||||||
class EditEntryScreen extends BasedScreen {
|
class EditEntryScreen extends BasedScreen {
|
||||||
|
@ -17,7 +19,7 @@ class EditEntryScreen extends BasedScreen {
|
||||||
State<EditEntryScreen> createState() => _EditEntryScreen();
|
State<EditEntryScreen> createState() => _EditEntryScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _EditEntryScreen extends State<EditEntryScreen> {
|
class _EditEntryScreen extends BasedState<EditEntryScreen> {
|
||||||
final gramsController = TextEditingController();
|
final gramsController = TextEditingController();
|
||||||
final productNameController = TextEditingController();
|
final productNameController = TextEditingController();
|
||||||
List<Product> products = [];
|
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 {
|
Future<double?> _parseDouble(String text, String name) async {
|
||||||
try {
|
try {
|
||||||
return double.parse(text.replaceAll(",", "."));
|
return double.parse(text.replaceAll(",", "."));
|
||||||
|
@ -123,27 +116,20 @@ class _EditEntryScreen extends State<EditEntryScreen> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: appBar(),
|
||||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
|
||||||
title: Text("🅵🅾🅾🅳🅴🆁", style: logoStyle(context)),
|
|
||||||
),
|
|
||||||
body: Center(
|
body: Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
constraints: const BoxConstraints(maxWidth: 720),
|
constraints: const BoxConstraints(maxWidth: 720),
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
child: ListView(children: <Widget>[
|
child: ListView(children: <Widget>[
|
||||||
TextFormField(
|
FTextInput(
|
||||||
decoration: const InputDecoration(
|
labelText: 'Product name',
|
||||||
labelText: 'Product name',
|
|
||||||
),
|
|
||||||
controller: productNameController,
|
controller: productNameController,
|
||||||
onChanged: (_) => _getProducts(),
|
onChanged: (_) => _getProducts(),
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
),
|
),
|
||||||
TextFormField(
|
FTextInput(
|
||||||
decoration: const InputDecoration(
|
labelText: 'Grams',
|
||||||
labelText: 'Grams',
|
|
||||||
),
|
|
||||||
keyboardType:
|
keyboardType:
|
||||||
const TextInputType.numberWithOptions(decimal: true),
|
const TextInputType.numberWithOptions(decimal: true),
|
||||||
inputFormatters: <TextInputFormatter>[
|
inputFormatters: <TextInputFormatter>[
|
||||||
|
@ -190,20 +176,21 @@ class _EditEntryScreen extends State<EditEntryScreen> {
|
||||||
floatingActionButton: Row(
|
floatingActionButton: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
FloatingActionButton(
|
FActionButton(
|
||||||
onPressed: _findProductByBarCode,
|
onPressed: _findProductByBarCode,
|
||||||
heroTag: null,
|
icon: Icons.photo_camera,
|
||||||
child: const Icon(Icons.photo_camera),
|
|
||||||
),
|
),
|
||||||
FloatingActionButton(
|
const SizedBox(width: 10),
|
||||||
|
FActionButton(
|
||||||
onPressed: _deleteEntry,
|
onPressed: _deleteEntry,
|
||||||
heroTag: null,
|
tag: "fap1",
|
||||||
child: const Icon(Icons.delete),
|
icon: Icons.delete,
|
||||||
),
|
),
|
||||||
FloatingActionButton(
|
const SizedBox(width: 10),
|
||||||
|
FActionButton(
|
||||||
onPressed: _saveEntry,
|
onPressed: _saveEntry,
|
||||||
heroTag: null,
|
tag: "fap2",
|
||||||
child: const Icon(Icons.save),
|
icon: Icons.save,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:fooder/screens/based.dart';
|
import 'package:fooder/screens/based.dart';
|
||||||
import 'package:fooder/screens/add_entry.dart';
|
import 'package:fooder/screens/add_entry.dart';
|
||||||
|
import 'package:fooder/screens/add_meal.dart';
|
||||||
import 'package:fooder/models/diary.dart';
|
import 'package:fooder/models/diary.dart';
|
||||||
import 'package:fooder/widgets/summary.dart';
|
import 'package:fooder/widgets/summary.dart';
|
||||||
import 'package:fooder/widgets/meal.dart';
|
import 'package:fooder/widgets/meal.dart';
|
||||||
import 'package:fooder/components/sliver.dart';
|
import 'package:fooder/components/sliver.dart';
|
||||||
import 'package:fooder/components/date_picker.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 {
|
class MainScreen extends BasedScreen {
|
||||||
const MainScreen({super.key, required super.apiClient});
|
const MainScreen({super.key, required super.apiClient});
|
||||||
|
@ -43,6 +44,10 @@ class _MainScreen extends BasedState<MainScreen> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _addEntry() async {
|
Future<void> _addEntry() async {
|
||||||
|
if (diary == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await Navigator.push(
|
await Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
|
@ -52,60 +57,20 @@ class _MainScreen extends BasedState<MainScreen> {
|
||||||
).then((_) => _asyncInitState());
|
).then((_) => _asyncInitState());
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget floatingActionButton(BuildContext context) {
|
Future<void> _addMeal(context) async {
|
||||||
var theme = Theme.of(context);
|
if (diary == null) {
|
||||||
var colorScheme = theme.colorScheme;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return Container(
|
await Navigator.push(
|
||||||
height: 64,
|
context,
|
||||||
width: 64,
|
MaterialPageRoute(
|
||||||
decoration: BoxDecoration(
|
builder: (context) => AddMealScreen(
|
||||||
borderRadius: BorderRadius.circular(32),
|
apiClient: widget.apiClient,
|
||||||
boxShadow: [
|
diary: diary!,
|
||||||
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,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
).then((_) => _asyncInitState());
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -133,7 +98,9 @@ class _MainScreen extends BasedState<MainScreen> {
|
||||||
apiClient: widget.apiClient,
|
apiClient: widget.apiClient,
|
||||||
refreshParent: _asyncInitState,
|
refreshParent: _asyncInitState,
|
||||||
initiallyExpanded: i == 0,
|
initiallyExpanded: i == 0,
|
||||||
|
showText: showText,
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 200),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -149,7 +116,18 @@ class _MainScreen extends BasedState<MainScreen> {
|
||||||
appBar: appBar(),
|
appBar: appBar(),
|
||||||
bottomNavigationBar: navBar(),
|
bottomNavigationBar: navBar(),
|
||||||
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
|
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:flutter/material.dart';
|
||||||
import 'package:fooder/models/entry.dart';
|
import 'package:fooder/models/entry.dart';
|
||||||
import 'package:fooder/widgets/macroEntry.dart';
|
import 'package:fooder/widgets/macro.dart';
|
||||||
import 'dart:core';
|
import 'dart:core';
|
||||||
|
|
||||||
class EntryHeader extends StatelessWidget {
|
class EntryHeader extends StatelessWidget {
|
||||||
|
@ -12,14 +12,17 @@ class EntryHeader extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Row(
|
return Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Padding(
|
Expanded(
|
||||||
padding: const EdgeInsets.all(8),
|
child: Padding(
|
||||||
child: Text(
|
padding: const EdgeInsets.all(8),
|
||||||
entry.product.name,
|
child: Text(
|
||||||
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
|
entry.product.name,
|
||||||
color: Theme.of(context).colorScheme.onPrimary,
|
overflow: TextOverflow.fade,
|
||||||
fontWeight: FontWeight.bold,
|
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
|
||||||
),
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
|
@ -28,7 +31,7 @@ class EntryHeader extends StatelessWidget {
|
||||||
child: Text(
|
child: Text(
|
||||||
"${entry.grams.toStringAsFixed(0)} g",
|
"${entry.grams.toStringAsFixed(0)} g",
|
||||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
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 'package:flutter/material.dart';
|
||||||
|
import 'dart:core';
|
||||||
|
|
||||||
class MacroWidget extends StatelessWidget {
|
class MacroHeaderWidget extends StatelessWidget {
|
||||||
final double? amount;
|
static const double padY = 4;
|
||||||
final double? calories;
|
static const double padX = 8;
|
||||||
final double? fiber;
|
|
||||||
final double protein;
|
|
||||||
final double carb;
|
|
||||||
final double fat;
|
|
||||||
final TextStyle style;
|
|
||||||
final Widget? child;
|
|
||||||
|
|
||||||
const MacroWidget({
|
final bool? fiber;
|
||||||
|
final bool? calories;
|
||||||
|
final Alignment alignment;
|
||||||
|
|
||||||
|
const MacroHeaderWidget({
|
||||||
super.key,
|
super.key,
|
||||||
this.calories,
|
this.fiber = false,
|
||||||
this.amount,
|
this.calories = false,
|
||||||
this.child,
|
this.alignment = Alignment.centerLeft,
|
||||||
this.fiber,
|
|
||||||
required this.protein,
|
|
||||||
required this.carb,
|
|
||||||
required this.fat,
|
|
||||||
required this.style,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var elements = <Widget>[
|
var elements = <String>[
|
||||||
Expanded(
|
"C(g)",
|
||||||
flex: 1,
|
"F(g)",
|
||||||
child: Text(
|
"P(g)",
|
||||||
"C: ${carb.toStringAsFixed(1)}g",
|
];
|
||||||
style: style,
|
|
||||||
textAlign: TextAlign.center,
|
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(
|
child: Row(
|
||||||
flex: 1,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
child: Text(
|
children: children,
|
||||||
"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,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
if (fiber != null) {
|
||||||
elements.add(
|
elements.add(
|
||||||
Expanded(
|
fiber!.toStringAsFixed(1),
|
||||||
flex: 1,
|
|
||||||
child: Text(
|
|
||||||
"f: ${fiber!.toStringAsFixed(1)}g",
|
|
||||||
style: style,
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (calories != null) {
|
if (calories != null) {
|
||||||
elements.add(
|
elements.add(
|
||||||
Expanded(
|
calories!.toStringAsFixed(0),
|
||||||
flex: 1,
|
);
|
||||||
child: Text(
|
}
|
||||||
"${calories!.toStringAsFixed(1)} kcal",
|
|
||||||
style: style,
|
var children = <Widget>[];
|
||||||
textAlign: TextAlign.center,
|
|
||||||
|
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) {
|
if (alignment == Alignment.centerLeft) {
|
||||||
elements.add(
|
children.add(const Spacer());
|
||||||
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(""),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.symmetric(
|
||||||
top: 4.0,
|
vertical: padY,
|
||||||
bottom: 4.0,
|
horizontal: padX,
|
||||||
left: 8.0,
|
|
||||||
right: 8.0,
|
|
||||||
),
|
),
|
||||||
child: Row(
|
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:flutter/material.dart';
|
||||||
import 'package:fooder/models/meal.dart';
|
import 'package:fooder/models/meal.dart';
|
||||||
import 'package:fooder/widgets/entry.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/edit_entry.dart';
|
||||||
import 'package:fooder/screens/meal.dart';
|
|
||||||
import 'package:fooder/client.dart';
|
import 'package:fooder/client.dart';
|
||||||
import 'dart:core';
|
import 'dart:core';
|
||||||
|
|
||||||
|
@ -16,14 +15,17 @@ class MealHeader extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Row(
|
return Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Padding(
|
Expanded(
|
||||||
padding: const EdgeInsets.all(8),
|
child: Padding(
|
||||||
child: Text(
|
padding: const EdgeInsets.all(8),
|
||||||
meal.name,
|
child: Text(
|
||||||
style: Theme.of(context).textTheme.headlineSmall!.copyWith(
|
meal.name,
|
||||||
color: Theme.of(context).colorScheme.onPrimary,
|
overflow: TextOverflow.fade,
|
||||||
fontWeight: FontWeight.bold,
|
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 Meal meal;
|
||||||
final ApiClient apiClient;
|
final ApiClient apiClient;
|
||||||
final Function() refreshParent;
|
final Function() refreshParent;
|
||||||
|
final Function(String) showText;
|
||||||
final bool initiallyExpanded;
|
final bool initiallyExpanded;
|
||||||
|
|
||||||
const MealWidget({
|
const MealWidget({
|
||||||
|
@ -45,19 +48,73 @@ class MealWidget extends StatelessWidget {
|
||||||
required this.apiClient,
|
required this.apiClient,
|
||||||
required this.refreshParent,
|
required this.refreshParent,
|
||||||
required this.initiallyExpanded,
|
required this.initiallyExpanded,
|
||||||
|
required this.showText,
|
||||||
});
|
});
|
||||||
|
|
||||||
Future<void> _editMeal(context) async {
|
Future<void> saveMeal(context) async {
|
||||||
await Navigator.push(
|
TextEditingController textFieldController = TextEditingController();
|
||||||
context,
|
textFieldController.text = meal.name;
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => MealScreen(
|
showDialog(
|
||||||
apiClient: apiClient,
|
context: context,
|
||||||
meal: meal,
|
builder: (context) {
|
||||||
refresh: refreshParent,
|
return AlertDialog(
|
||||||
),
|
title: const Text('Save Meal'),
|
||||||
),
|
content: TextField(
|
||||||
).then((_) => refreshParent());
|
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 {
|
Future<void> _editEntry(context, entry) async {
|
||||||
|
@ -84,61 +141,61 @@ class MealWidget extends StatelessWidget {
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: Card(
|
child: Card(
|
||||||
elevation: 4,
|
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
shadowColor: colorScheme.primary.withOpacity(1.0),
|
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(24),
|
borderRadius: BorderRadius.circular(24),
|
||||||
),
|
),
|
||||||
child: SizedBox(
|
child: Container(
|
||||||
width: width,
|
constraints: BoxConstraints(maxWidth: width),
|
||||||
child: Container(
|
color: colorScheme.surface.withOpacity(0.2),
|
||||||
decoration: BoxDecoration(
|
child: ExpansionTile(
|
||||||
gradient: LinearGradient(
|
iconColor: colorScheme.onSurface,
|
||||||
colors: [
|
collapsedIconColor: colorScheme.onSurface,
|
||||||
colorScheme.primary.withOpacity(0.6),
|
initiallyExpanded: initiallyExpanded,
|
||||||
colorScheme.secondary.withOpacity(0.5),
|
enableFeedback: true,
|
||||||
],
|
title: Padding(
|
||||||
),
|
padding: const EdgeInsets.all(8),
|
||||||
),
|
child: Column(
|
||||||
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,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
for (var (i, entry) in meal.entries.indexed)
|
MealHeader(meal: meal),
|
||||||
ListTile(
|
const MacroHeaderWidget(
|
||||||
title: EntryWidget(
|
calories: true,
|
||||||
entry: entry,
|
),
|
||||||
),
|
MacroEntryWidget(
|
||||||
tileColor: i % 2 == 0
|
protein: meal.protein,
|
||||||
? colorScheme.secondary.withOpacity(0.1)
|
carb: meal.carb,
|
||||||
: Colors.transparent,
|
fat: meal.fat,
|
||||||
onTap: () => _editEntry(context, entry),
|
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 'package:fooder/widgets/macro.dart';
|
||||||
import 'dart:core';
|
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 {
|
class PresetWidget extends StatelessWidget {
|
||||||
final Preset preset;
|
final Preset preset;
|
||||||
|
|
||||||
|
@ -14,24 +41,21 @@ class PresetWidget extends StatelessWidget {
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Row(
|
PresetHeader(
|
||||||
children: <Widget>[
|
title: preset.name,
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
preset.name,
|
|
||||||
style: Theme.of(context).textTheme.titleLarge,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text("${preset.calories.toStringAsFixed(1)} kcal"),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
MacroWidget(
|
const MacroHeaderWidget(
|
||||||
|
fiber: true,
|
||||||
|
calories: true,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
),
|
||||||
|
MacroEntryWidget(
|
||||||
protein: preset.protein,
|
protein: preset.protein,
|
||||||
carb: preset.carb,
|
carb: preset.carb,
|
||||||
fat: preset.fat,
|
fat: preset.fat,
|
||||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
fiber: preset.fiber,
|
||||||
color: Theme.of(context).colorScheme.secondary,
|
calories: preset.calories,
|
||||||
),
|
alignment: Alignment.center,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -3,6 +3,33 @@ import 'package:fooder/models/product.dart';
|
||||||
import 'package:fooder/widgets/macro.dart';
|
import 'package:fooder/widgets/macro.dart';
|
||||||
import 'dart:core';
|
import 'dart:core';
|
||||||
|
|
||||||
|
class 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 {
|
class ProductWidget extends StatelessWidget {
|
||||||
final Product product;
|
final Product product;
|
||||||
|
|
||||||
|
@ -14,26 +41,21 @@ class ProductWidget extends StatelessWidget {
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Row(
|
ProductHeader(
|
||||||
children: <Widget>[
|
title: product.name,
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
product.name,
|
|
||||||
style: Theme.of(context).textTheme.titleLarge,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text("${product.calories.toStringAsFixed(1)} kcal"),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
MacroWidget(
|
const MacroHeaderWidget(
|
||||||
|
fiber: true,
|
||||||
|
calories: true,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
),
|
||||||
|
MacroEntryWidget(
|
||||||
protein: product.protein,
|
protein: product.protein,
|
||||||
carb: product.carb,
|
carb: product.carb,
|
||||||
fat: product.fat,
|
fat: product.fat,
|
||||||
fiber: product.fiber,
|
fiber: product.fiber,
|
||||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
calories: product.calories,
|
||||||
color: Theme.of(context).colorScheme.secondary,
|
alignment: Alignment.center,
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,15 +1,13 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:fooder/models/diary.dart';
|
import 'package:fooder/models/diary.dart';
|
||||||
import 'package:fooder/widgets/macroEntry.dart';
|
import 'package:fooder/widgets/macro.dart';
|
||||||
import 'package:fooder/screens/add_meal.dart';
|
|
||||||
import 'package:fooder/client.dart';
|
import 'package:fooder/client.dart';
|
||||||
import 'dart:core';
|
import 'dart:core';
|
||||||
|
|
||||||
class SummaryHeader extends StatelessWidget {
|
class SummaryHeader extends StatelessWidget {
|
||||||
final Diary diary;
|
final Diary diary;
|
||||||
final Function addMeal;
|
|
||||||
|
|
||||||
const SummaryHeader({super.key, required this.addMeal, required this.diary});
|
const SummaryHeader({super.key, required this.diary});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -20,21 +18,12 @@ class SummaryHeader extends StatelessWidget {
|
||||||
child: Text(
|
child: Text(
|
||||||
"Summary",
|
"Summary",
|
||||||
style: Theme.of(context).textTheme.headlineSmall!.copyWith(
|
style: Theme.of(context).textTheme.headlineSmall!.copyWith(
|
||||||
color: Theme.of(context).colorScheme.onPrimary,
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
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.apiClient,
|
||||||
required this.refreshParent});
|
required this.refreshParent});
|
||||||
|
|
||||||
Future<void> _addMeal(context) async {
|
|
||||||
await Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => AddMealScreen(
|
|
||||||
apiClient: apiClient,
|
|
||||||
diary: diary,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
).then((_) => refreshParent());
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var theme = Theme.of(context);
|
var theme = Theme.of(context);
|
||||||
|
@ -77,40 +54,28 @@ class SummaryWidget extends StatelessWidget {
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: Card(
|
child: Card(
|
||||||
elevation: 4,
|
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
shadowColor: colorScheme.primary.withOpacity(1.0),
|
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(24),
|
borderRadius: BorderRadius.circular(24),
|
||||||
),
|
),
|
||||||
child: SizedBox(
|
child: Container(
|
||||||
width: width,
|
constraints: BoxConstraints(maxWidth: width),
|
||||||
child: Container(
|
color: colorScheme.surface.withOpacity(0.2),
|
||||||
decoration: BoxDecoration(
|
child: Padding(
|
||||||
gradient: LinearGradient(
|
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 24),
|
||||||
colors: [
|
child: Column(
|
||||||
colorScheme.primary.withOpacity(0.6),
|
children: <Widget>[
|
||||||
colorScheme.secondary.withOpacity(0.5),
|
SummaryHeader(diary: diary),
|
||||||
],
|
const MacroHeaderWidget(
|
||||||
),
|
calories: true,
|
||||||
),
|
),
|
||||||
child: Padding(
|
MacroEntryWidget(
|
||||||
padding:
|
protein: diary.protein,
|
||||||
const EdgeInsets.symmetric(vertical: 12, horizontal: 24),
|
carb: diary.carb,
|
||||||
child: Column(
|
fat: diary.fat,
|
||||||
children: <Widget>[
|
calories: diary.calories,
|
||||||
SummaryHeader(diary: diary, addMeal: _addMeal),
|
),
|
||||||
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 */; };
|
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
|
||||||
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
|
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
|
||||||
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
|
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 */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
@ -60,11 +62,14 @@
|
||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference 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; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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 */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
@ -85,6 +95,7 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
DC768C2964C710CDD24D0DB4 /* Pods_RunnerTests.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
@ -92,12 +103,27 @@
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
47A87A2D935C9FD21BC18BA6 /* Pods_Runner.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup 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 */ = {
|
331C80D6294CF71000263BE5 /* RunnerTests */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -125,6 +151,7 @@
|
||||||
331C80D6294CF71000263BE5 /* RunnerTests */,
|
331C80D6294CF71000263BE5 /* RunnerTests */,
|
||||||
33CC10EE2044A3C60003C045 /* Products */,
|
33CC10EE2044A3C60003C045 /* Products */,
|
||||||
D73912EC22F37F3D000D13A0 /* Frameworks */,
|
D73912EC22F37F3D000D13A0 /* Frameworks */,
|
||||||
|
076AC79CB527EDDF03C6C1BF /* Pods */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
@ -175,6 +202,8 @@
|
||||||
D73912EC22F37F3D000D13A0 /* Frameworks */ = {
|
D73912EC22F37F3D000D13A0 /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
17BEB3BB725731AD7E5B80B1 /* Pods_Runner.framework */,
|
||||||
|
465D02A290608CA511C1F4CA /* Pods_RunnerTests.framework */,
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -186,6 +215,7 @@
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
|
EBBB44C74E6664565AAD7743 /* [CP] Check Pods Manifest.lock */,
|
||||||
331C80D1294CF70F00263BE5 /* Sources */,
|
331C80D1294CF70F00263BE5 /* Sources */,
|
||||||
331C80D2294CF70F00263BE5 /* Frameworks */,
|
331C80D2294CF70F00263BE5 /* Frameworks */,
|
||||||
331C80D3294CF70F00263BE5 /* Resources */,
|
331C80D3294CF70F00263BE5 /* Resources */,
|
||||||
|
@ -204,11 +234,13 @@
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
|
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
|
DD4A3E0D06F0EB3D92595679 /* [CP] Check Pods Manifest.lock */,
|
||||||
33CC10E92044A3C60003C045 /* Sources */,
|
33CC10E92044A3C60003C045 /* Sources */,
|
||||||
33CC10EA2044A3C60003C045 /* Frameworks */,
|
33CC10EA2044A3C60003C045 /* Frameworks */,
|
||||||
33CC10EB2044A3C60003C045 /* Resources */,
|
33CC10EB2044A3C60003C045 /* Resources */,
|
||||||
33CC110E2044A8840003C045 /* Bundle Framework */,
|
33CC110E2044A8840003C045 /* Bundle Framework */,
|
||||||
3399D490228B24CF009A79C7 /* ShellScript */,
|
3399D490228B24CF009A79C7 /* ShellScript */,
|
||||||
|
3020AFE6AB38B106E5D2E587 /* [CP] Embed Pods Frameworks */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
|
@ -227,7 +259,7 @@
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastSwiftUpdateCheck = 0920;
|
LastSwiftUpdateCheck = 0920;
|
||||||
LastUpgradeCheck = 1430;
|
LastUpgradeCheck = 1510;
|
||||||
ORGANIZATIONNAME = "";
|
ORGANIZATIONNAME = "";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
331C80D4294CF70F00263BE5 = {
|
331C80D4294CF70F00263BE5 = {
|
||||||
|
@ -290,6 +322,23 @@
|
||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXShellScriptBuildPhase 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 */ = {
|
3399D490228B24CF009A79C7 /* ShellScript */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
alwaysOutOfDate = 1;
|
alwaysOutOfDate = 1;
|
||||||
|
@ -328,6 +377,50 @@
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
|
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 */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
@ -379,6 +472,7 @@
|
||||||
/* Begin XCBuildConfiguration section */
|
/* Begin XCBuildConfiguration section */
|
||||||
331C80DB294CF71000263BE5 /* Debug */ = {
|
331C80DB294CF71000263BE5 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = F971A3061D014BCFE5A477A9 /* Pods-RunnerTests.debug.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
@ -393,6 +487,7 @@
|
||||||
};
|
};
|
||||||
331C80DC294CF71000263BE5 /* Release */ = {
|
331C80DC294CF71000263BE5 /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = D32BEBE6FA5B351434300418 /* Pods-RunnerTests.release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
@ -407,6 +502,7 @@
|
||||||
};
|
};
|
||||||
331C80DD294CF71000263BE5 /* Profile */ = {
|
331C80DD294CF71000263BE5 /* Profile */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 19DEDDAC7F8C48D43A9E76CF /* Pods-RunnerTests.profile.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1430"
|
LastUpgradeVersion = "1510"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
|
|
@ -4,4 +4,7 @@
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:Runner.xcodeproj">
|
location = "group:Runner.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
|
<FileRef
|
||||||
|
location = "group:Pods/Pods.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
</Workspace>
|
</Workspace>
|
||||||
|
|
Loading…
Reference in a new issue