[UI craze] main screen implemented?
This commit is contained in:
		
							parent
							
								
									90fad4a0ac
								
							
						
					
					
						commit
						66b88f64fe
					
				
					 17 changed files with 815 additions and 142 deletions
				
			
		| 
						 | 
					@ -1,7 +1,9 @@
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FAppBar extends StatelessWidget implements PreferredSizeWidget {
 | 
					class FAppBar extends StatelessWidget implements PreferredSizeWidget {
 | 
				
			||||||
  const FAppBar({super.key});
 | 
					  final List<Widget> actions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const FAppBar({super.key, required this.actions});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
| 
						 | 
					@ -13,6 +15,7 @@ class FAppBar extends StatelessWidget implements PreferredSizeWidget {
 | 
				
			||||||
      child: AppBar(
 | 
					      child: AppBar(
 | 
				
			||||||
        backgroundColor: Colors.transparent,
 | 
					        backgroundColor: Colors.transparent,
 | 
				
			||||||
        elevation: 0,
 | 
					        elevation: 0,
 | 
				
			||||||
 | 
					        actions: actions,
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,8 +21,20 @@ class FButton extends StatelessWidget {
 | 
				
			||||||
        child: Container(
 | 
					        child: Container(
 | 
				
			||||||
          padding: EdgeInsets.symmetric(vertical: insidePadding),
 | 
					          padding: EdgeInsets.symmetric(vertical: insidePadding),
 | 
				
			||||||
          decoration: BoxDecoration(
 | 
					          decoration: BoxDecoration(
 | 
				
			||||||
            color: colorScheme.primary,
 | 
					            gradient: LinearGradient(
 | 
				
			||||||
 | 
					              colors: [
 | 
				
			||||||
 | 
					                colorScheme.primary.withOpacity(0.5),
 | 
				
			||||||
 | 
					                colorScheme.secondary.withOpacity(0.5),
 | 
				
			||||||
 | 
					              ],
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
            borderRadius: BorderRadius.circular(4),
 | 
					            borderRadius: BorderRadius.circular(4),
 | 
				
			||||||
 | 
					            boxShadow: [
 | 
				
			||||||
 | 
					              BoxShadow(
 | 
				
			||||||
 | 
					                color: colorScheme.primary.withOpacity(0.3),
 | 
				
			||||||
 | 
					                blurRadius: 5,
 | 
				
			||||||
 | 
					                offset: const Offset(0, 5),
 | 
				
			||||||
 | 
					              )
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
          child: Center(
 | 
					          child: Center(
 | 
				
			||||||
            child: Text(
 | 
					            child: Text(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,11 +28,12 @@ class FDateItemWidget extends StatelessWidget {
 | 
				
			||||||
        onDatePicked(date);
 | 
					        onDatePicked(date);
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      child: Container(
 | 
					      child: Container(
 | 
				
			||||||
        width: 100,
 | 
					        width: picked? 100: 50,
 | 
				
			||||||
        decoration: BoxDecoration(
 | 
					        decoration: BoxDecoration(
 | 
				
			||||||
          borderRadius: BorderRadius.circular(50),
 | 
					          borderRadius: BorderRadius.circular(50),
 | 
				
			||||||
          border: Border.all(
 | 
					          border: Border.all(
 | 
				
			||||||
            color: colorScheme.onPrimary,
 | 
					            // color: picked ? colorScheme.onPrimary : Colors.transparent,
 | 
				
			||||||
 | 
					            color: Colors.transparent,
 | 
				
			||||||
            width: 2,
 | 
					            width: 2,
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
          color: picked ? colorScheme.onPrimary.withOpacity(0.25) : Colors.transparent,
 | 
					          color: picked ? colorScheme.onPrimary.withOpacity(0.25) : Colors.transparent,
 | 
				
			||||||
| 
						 | 
					@ -44,7 +45,7 @@ class FDateItemWidget extends StatelessWidget {
 | 
				
			||||||
              dayOfTheWeekMap[date.weekday]!,
 | 
					              dayOfTheWeekMap[date.weekday]!,
 | 
				
			||||||
              style: TextStyle(
 | 
					              style: TextStyle(
 | 
				
			||||||
                color: colorScheme.onPrimary,
 | 
					                color: colorScheme.onPrimary,
 | 
				
			||||||
                fontSize: 24,
 | 
					                fontSize: picked ? 24: 12,
 | 
				
			||||||
                fontWeight: FontWeight.bold,
 | 
					                fontWeight: FontWeight.bold,
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
| 
						 | 
					@ -52,7 +53,7 @@ class FDateItemWidget extends StatelessWidget {
 | 
				
			||||||
              '${date.day}.${date.month}',
 | 
					              '${date.day}.${date.month}',
 | 
				
			||||||
              style: TextStyle(
 | 
					              style: TextStyle(
 | 
				
			||||||
                color: colorScheme.onPrimary,
 | 
					                color: colorScheme.onPrimary,
 | 
				
			||||||
                fontSize: 24,
 | 
					                fontSize: picked ? 24: 12,
 | 
				
			||||||
                fontWeight: FontWeight.bold,
 | 
					                fontWeight: FontWeight.bold,
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
| 
						 | 
					@ -102,28 +103,35 @@ class _FDatePickerWidgetState extends State<FDatePickerWidget> {
 | 
				
			||||||
      child: Center(
 | 
					      child: Center(
 | 
				
			||||||
        child: ListView(
 | 
					        child: ListView(
 | 
				
			||||||
          scrollDirection: Axis.horizontal,
 | 
					          scrollDirection: Axis.horizontal,
 | 
				
			||||||
 | 
					          padding: const EdgeInsets.symmetric(horizontal: 20),
 | 
				
			||||||
          shrinkWrap: true,
 | 
					          shrinkWrap: true,
 | 
				
			||||||
          children: <Widget>[
 | 
					          children: <Widget>[
 | 
				
			||||||
            SizedBox(width: 25),
 | 
					            FDateItemWidget(date: date.add(Duration(days: -3)), onDatePicked: onDatePicked),
 | 
				
			||||||
            FDateItemWidget(date: date.add(Duration(days: -2)), onDatePicked: onDatePicked),
 | 
					            FDateItemWidget(date: date.add(Duration(days: -2)), onDatePicked: onDatePicked),
 | 
				
			||||||
            SizedBox(width: 25),
 | 
					 | 
				
			||||||
            FDateItemWidget(date: date.add(Duration(days: -1)), onDatePicked: onDatePicked),
 | 
					            FDateItemWidget(date: date.add(Duration(days: -1)), onDatePicked: onDatePicked),
 | 
				
			||||||
            SizedBox(width: 25),
 | 
					 | 
				
			||||||
            FDateItemWidget(date: date, onDatePicked: onDatePicked, picked: true),
 | 
					            FDateItemWidget(date: date, onDatePicked: onDatePicked, picked: true),
 | 
				
			||||||
            SizedBox(width: 25),
 | 
					 | 
				
			||||||
            FDateItemWidget(date: date.add(Duration(days: 1)), onDatePicked: onDatePicked),
 | 
					            FDateItemWidget(date: date.add(Duration(days: 1)), onDatePicked: onDatePicked),
 | 
				
			||||||
            SizedBox(width: 25),
 | 
					 | 
				
			||||||
            FDateItemWidget(date: date.add(Duration(days: 2)), onDatePicked: onDatePicked),
 | 
					            FDateItemWidget(date: date.add(Duration(days: 2)), onDatePicked: onDatePicked),
 | 
				
			||||||
            Container(
 | 
					            Container(
 | 
				
			||||||
              width: 100,
 | 
					              width: 50,
 | 
				
			||||||
              child: IconButton(
 | 
					              child: IconButton(
 | 
				
			||||||
                icon: Icon(
 | 
					                icon: Icon(
 | 
				
			||||||
                  Icons.calendar_month,
 | 
					                  Icons.calendar_month,
 | 
				
			||||||
                  color: colorScheme.onPrimary,
 | 
					                  color: colorScheme.onPrimary,
 | 
				
			||||||
                  size: 40,
 | 
					                  size: 20,
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                onPressed: () {
 | 
					                onPressed: () {
 | 
				
			||||||
                  onDatePicked(date.add(Duration(days: 1)));
 | 
					                  // open date picker
 | 
				
			||||||
 | 
					                  showDatePicker(
 | 
				
			||||||
 | 
					                    context: context,
 | 
				
			||||||
 | 
					                    initialDate: date,
 | 
				
			||||||
 | 
					                    firstDate: date.add(Duration(days: -365)),
 | 
				
			||||||
 | 
					                    lastDate: date.add(Duration(days: 365)),
 | 
				
			||||||
 | 
					                  ).then((value) {
 | 
				
			||||||
 | 
					                    if (value != null) {
 | 
				
			||||||
 | 
					                      onDatePicked(value);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                  });
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										64
									
								
								lib/components/navigationBar.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								lib/components/navigationBar.dart
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,64 @@
 | 
				
			||||||
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					import 'package:blur/blur.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FNavBar extends StatelessWidget  {
 | 
				
			||||||
 | 
					  final List<Widget> children;
 | 
				
			||||||
 | 
					  final double height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const FNavBar ({super.key, required this.children, this.height = 56});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    var theme = Theme.of(context);
 | 
				
			||||||
 | 
					    var colorScheme = theme.colorScheme;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return SafeArea(
 | 
				
			||||||
 | 
					      child: Padding(
 | 
				
			||||||
 | 
					        padding: EdgeInsets.all(12),
 | 
				
			||||||
 | 
					        child: Container(
 | 
				
			||||||
 | 
					          decoration: BoxDecoration(
 | 
				
			||||||
 | 
					            borderRadius: BorderRadius.circular(24),
 | 
				
			||||||
 | 
					            boxShadow: [
 | 
				
			||||||
 | 
					              BoxShadow(
 | 
				
			||||||
 | 
					                color: colorScheme.primary.withOpacity(0.3),
 | 
				
			||||||
 | 
					                blurRadius: 5,
 | 
				
			||||||
 | 
					                offset: const Offset(0, 5),
 | 
				
			||||||
 | 
					              )
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					          child: ClipRRect(
 | 
				
			||||||
 | 
					            borderRadius: BorderRadius.circular(24),
 | 
				
			||||||
 | 
					            child: Stack(
 | 
				
			||||||
 | 
					              children: [
 | 
				
			||||||
 | 
					                Blur(
 | 
				
			||||||
 | 
					                  blur: 10,
 | 
				
			||||||
 | 
					                  blurColor: colorScheme.primary.withOpacity(0.1),
 | 
				
			||||||
 | 
					                  child: Container(
 | 
				
			||||||
 | 
					                    width: MediaQuery.of(context).size.width,
 | 
				
			||||||
 | 
					                    height: height * children.length,
 | 
				
			||||||
 | 
					                    decoration: BoxDecoration(
 | 
				
			||||||
 | 
					                      gradient: LinearGradient(
 | 
				
			||||||
 | 
					                        colors: [
 | 
				
			||||||
 | 
					                          colorScheme.primary.withOpacity(0.1),
 | 
				
			||||||
 | 
					                          colorScheme.secondary.withOpacity(0.1),
 | 
				
			||||||
 | 
					                        ],
 | 
				
			||||||
 | 
					                      ),
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                Container(
 | 
				
			||||||
 | 
					                  width: MediaQuery.of(context).size.width,
 | 
				
			||||||
 | 
					                  height: height * children.length,
 | 
				
			||||||
 | 
					                  child: Column(
 | 
				
			||||||
 | 
					                    mainAxisAlignment: MainAxisAlignment.center,
 | 
				
			||||||
 | 
					                    children: children,
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					              ],
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,48 @@
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					import 'package:blur/blur.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ClipShadowPath extends StatelessWidget {
 | 
				
			||||||
 | 
					  final Shadow shadow;
 | 
				
			||||||
 | 
					  final CustomClipper<Path> clipper;
 | 
				
			||||||
 | 
					  final Widget child;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ClipShadowPath({
 | 
				
			||||||
 | 
					    required this.shadow,
 | 
				
			||||||
 | 
					    required this.clipper,
 | 
				
			||||||
 | 
					    required this.child,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    return CustomPaint(
 | 
				
			||||||
 | 
					      painter: _ClipShadowShadowPainter(
 | 
				
			||||||
 | 
					        clipper: this.clipper,
 | 
				
			||||||
 | 
					        shadow: this.shadow,
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					      child: ClipPath(child: child, clipper: this.clipper),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class _ClipShadowShadowPainter extends CustomPainter {
 | 
				
			||||||
 | 
					  final Shadow shadow;
 | 
				
			||||||
 | 
					  final CustomClipper<Path> clipper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _ClipShadowShadowPainter({required this.shadow, required this.clipper});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  void paint(Canvas canvas, Size size) {
 | 
				
			||||||
 | 
					    var paint = shadow.toPaint();
 | 
				
			||||||
 | 
					    var clipPath = clipper.getClip(size).shift(shadow.offset);
 | 
				
			||||||
 | 
					    canvas.drawPath(clipPath, paint);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  bool shouldRepaint(CustomPainter oldDelegate) {
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class BackgroundWave extends StatelessWidget {
 | 
					class BackgroundWave extends StatelessWidget {
 | 
				
			||||||
  final double height;
 | 
					  final double height;
 | 
				
			||||||
| 
						 | 
					@ -12,16 +56,30 @@ class BackgroundWave extends StatelessWidget {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return SizedBox(
 | 
					    return SizedBox(
 | 
				
			||||||
      height: height,
 | 
					      height: height,
 | 
				
			||||||
      child: ClipPath(
 | 
					      child: ClipShadowPath(
 | 
				
			||||||
          clipper: BackgroundWaveClipper(),
 | 
					        clipper: BackgroundWaveClipper(),
 | 
				
			||||||
 | 
					        shadow: BoxShadow(
 | 
				
			||||||
 | 
					          blurRadius: 5,
 | 
				
			||||||
 | 
					          color: colorScheme.primary.withOpacity(0.3),
 | 
				
			||||||
 | 
					          offset: const Offset(0, 5),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        child: Blur(
 | 
				
			||||||
 | 
					          blur: 10,
 | 
				
			||||||
 | 
					          blurColor: colorScheme.primary.withOpacity(0.1),
 | 
				
			||||||
          child: Container(
 | 
					          child: Container(
 | 
				
			||||||
            width: MediaQuery.of(context).size.width,
 | 
					            width: MediaQuery.of(context).size.width,
 | 
				
			||||||
            height: height,
 | 
					            height: height,
 | 
				
			||||||
            decoration: BoxDecoration(
 | 
					            decoration: BoxDecoration(
 | 
				
			||||||
                gradient: LinearGradient(
 | 
					              gradient: LinearGradient(
 | 
				
			||||||
              colors: [colorScheme.primary, colorScheme.secondary],
 | 
					                colors: [
 | 
				
			||||||
            )),
 | 
					                  colorScheme.primary.withOpacity(0.1),
 | 
				
			||||||
          )),
 | 
					                  colorScheme.secondary.withOpacity(0.1),
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -33,14 +91,14 @@ class BackgroundWaveClipper extends CustomClipper<Path> {
 | 
				
			||||||
    path.lineTo(0.0, size.height);
 | 
					    path.lineTo(0.0, size.height);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var firstCurve = Offset(0, size.height - 20);
 | 
					    var firstCurve = Offset(0, size.height - 20);
 | 
				
			||||||
    var lastCurve = Offset(30, size.height - 20);
 | 
					    var lastCurve = Offset(40, size.height - 20);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    path.quadraticBezierTo(
 | 
					    path.quadraticBezierTo(
 | 
				
			||||||
        firstCurve.dx, firstCurve.dy, lastCurve.dx, lastCurve.dy,
 | 
					        firstCurve.dx, firstCurve.dy, lastCurve.dx, lastCurve.dy,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    firstCurve = Offset(0, size.height - 20);
 | 
					    firstCurve = Offset(0, size.height - 20);
 | 
				
			||||||
    lastCurve = Offset(size.width - 30, size.height - 20);
 | 
					    lastCurve = Offset(size.width - 40, size.height - 20);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    path.quadraticBezierTo(
 | 
					    path.quadraticBezierTo(
 | 
				
			||||||
        firstCurve.dx, firstCurve.dy, lastCurve.dx, lastCurve.dy,
 | 
					        firstCurve.dx, firstCurve.dy, lastCurve.dx, lastCurve.dy,
 | 
				
			||||||
| 
						 | 
					@ -72,13 +130,17 @@ class FSliverAppBar extends SliverPersistentHeaderDelegate {
 | 
				
			||||||
    var adjustedShrinkOffset = shrinkOffset > minExtent ? minExtent : shrinkOffset;
 | 
					    var adjustedShrinkOffset = shrinkOffset > minExtent ? minExtent : shrinkOffset;
 | 
				
			||||||
    double offset = (minExtent - adjustedShrinkOffset);
 | 
					    double offset = (minExtent - adjustedShrinkOffset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (offset < 4) {
 | 
				
			||||||
 | 
					      offset = 4;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return Stack(
 | 
					    return Stack(
 | 
				
			||||||
      children: [
 | 
					      children: [
 | 
				
			||||||
        const BackgroundWave(
 | 
					        const BackgroundWave(
 | 
				
			||||||
          height: 280,
 | 
					          height: 280,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        Positioned(
 | 
					        Positioned(
 | 
				
			||||||
          top: offset + 8,
 | 
					          top: offset,
 | 
				
			||||||
          child: child,
 | 
					          child: child,
 | 
				
			||||||
          left: 16,
 | 
					          left: 16,
 | 
				
			||||||
          right: 16,
 | 
					          right: 16,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,7 +20,7 @@ class AddEntryScreen extends BasedScreen {
 | 
				
			||||||
  State<AddEntryScreen> createState() => _AddEntryScreen();
 | 
					  State<AddEntryScreen> createState() => _AddEntryScreen();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class _AddEntryScreen extends State<AddEntryScreen> {
 | 
					class _AddEntryScreen extends BasedState<AddEntryScreen> {
 | 
				
			||||||
  final gramsController = TextEditingController();
 | 
					  final gramsController = TextEditingController();
 | 
				
			||||||
  final productNameController = TextEditingController();
 | 
					  final productNameController = TextEditingController();
 | 
				
			||||||
  Meal? meal;
 | 
					  Meal? meal;
 | 
				
			||||||
| 
						 | 
					@ -129,7 +129,7 @@ class _AddEntryScreen extends State<AddEntryScreen> {
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    return Scaffold(
 | 
					    return Scaffold(
 | 
				
			||||||
      extendBodyBehindAppBar: true,
 | 
					      extendBodyBehindAppBar: true,
 | 
				
			||||||
      appBar: FAppBar(),
 | 
					      appBar: appBar(),
 | 
				
			||||||
      body: Center(
 | 
					      body: Center(
 | 
				
			||||||
        child: Container(
 | 
					        child: Container(
 | 
				
			||||||
            constraints: const BoxConstraints(maxWidth: 720),
 | 
					            constraints: const BoxConstraints(maxWidth: 720),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,9 @@
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:fooder/client.dart';
 | 
					import 'package:fooder/client.dart';
 | 
				
			||||||
 | 
					import 'package:fooder/components/appBar.dart';
 | 
				
			||||||
 | 
					import 'package:fooder/components/navigationBar.dart';
 | 
				
			||||||
 | 
					import 'package:fooder/screens/login.dart';
 | 
				
			||||||
 | 
					import 'package:fooder/screens/main.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
TextStyle logoStyle(context) {
 | 
					TextStyle logoStyle(context) {
 | 
				
			||||||
  return Theme.of(context).textTheme.labelLarge!.copyWith(
 | 
					  return Theme.of(context).textTheme.labelLarge!.copyWith(
 | 
				
			||||||
| 
						 | 
					@ -14,6 +18,79 @@ abstract class BasedScreen extends StatefulWidget {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
abstract class BasedState<T extends BasedScreen> extends State<T> {
 | 
					abstract class BasedState<T extends BasedScreen> extends State<T> {
 | 
				
			||||||
 | 
					  void _logout() async {
 | 
				
			||||||
 | 
					    await widget.apiClient.logout();
 | 
				
			||||||
 | 
					    Navigator.pushReplacement(
 | 
				
			||||||
 | 
					      context,
 | 
				
			||||||
 | 
					      MaterialPageRoute(
 | 
				
			||||||
 | 
					        builder: (context) => LoginScreen(apiClient: widget.apiClient),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void backToDiary() {
 | 
				
			||||||
 | 
					    Navigator.pushReplacement(
 | 
				
			||||||
 | 
					      context,
 | 
				
			||||||
 | 
					      MaterialPageRoute(
 | 
				
			||||||
 | 
					        builder: (context) => MainScreen(apiClient: widget.apiClient),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FAppBar appBar() {
 | 
				
			||||||
 | 
					    return FAppBar(
 | 
				
			||||||
 | 
					      actions: [
 | 
				
			||||||
 | 
					        IconButton(
 | 
				
			||||||
 | 
					          icon: Icon(
 | 
				
			||||||
 | 
					            Icons.logout,
 | 
				
			||||||
 | 
					            color: Theme.of(context).colorScheme.onPrimary,
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					          onPressed: _logout,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FNavBar navBar() {
 | 
				
			||||||
 | 
					    return FNavBar(
 | 
				
			||||||
 | 
					      children: [
 | 
				
			||||||
 | 
					        Row(
 | 
				
			||||||
 | 
					          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
 | 
				
			||||||
 | 
					          children: [
 | 
				
			||||||
 | 
					            IconButton(
 | 
				
			||||||
 | 
					              icon: Icon(
 | 
				
			||||||
 | 
					                Icons.menu_book,
 | 
				
			||||||
 | 
					                color: Theme.of(context).colorScheme.onPrimary,
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					              onPressed: backToDiary,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            IconButton(
 | 
				
			||||||
 | 
					              icon: Icon(
 | 
				
			||||||
 | 
					                Icons.dinner_dining,
 | 
				
			||||||
 | 
					                color: Theme.of(context).colorScheme.onPrimary,
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					              onPressed: () => null,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            IconButton(
 | 
				
			||||||
 | 
					              icon: Icon(
 | 
				
			||||||
 | 
					                Icons.lunch_dining,
 | 
				
			||||||
 | 
					                color: Theme.of(context).colorScheme.onPrimary,
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					              onPressed: () => null,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            IconButton(
 | 
				
			||||||
 | 
					              icon: Icon(
 | 
				
			||||||
 | 
					                Icons.person,
 | 
				
			||||||
 | 
					                color: Theme.of(context).colorScheme.onPrimary,
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					              onPressed: () => null,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void showError(String message) {
 | 
					  void showError(String message) {
 | 
				
			||||||
    ScaffoldMessenger.of(context).showSnackBar(
 | 
					    ScaffoldMessenger.of(context).showSnackBar(
 | 
				
			||||||
      SnackBar(
 | 
					      SnackBar(
 | 
				
			||||||
| 
						 | 
					@ -22,9 +99,10 @@ abstract class BasedState<T extends BasedScreen> extends State<T> {
 | 
				
			||||||
          textAlign: TextAlign.center,
 | 
					          textAlign: TextAlign.center,
 | 
				
			||||||
          style: Theme.of(context).textTheme.bodyLarge!.copyWith(
 | 
					          style: Theme.of(context).textTheme.bodyLarge!.copyWith(
 | 
				
			||||||
            fontWeight: FontWeight.bold,
 | 
					            fontWeight: FontWeight.bold,
 | 
				
			||||||
 | 
					            color: Theme.of(context).colorScheme.onError,
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        backgroundColor: Theme.of(context).colorScheme.error,
 | 
					        backgroundColor: Theme.of(context).colorScheme.error.withOpacity(0.8),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					@ -37,9 +115,10 @@ abstract class BasedState<T extends BasedScreen> extends State<T> {
 | 
				
			||||||
          textAlign: TextAlign.center,
 | 
					          textAlign: TextAlign.center,
 | 
				
			||||||
          style: Theme.of(context).textTheme.bodyLarge!.copyWith(
 | 
					          style: Theme.of(context).textTheme.bodyLarge!.copyWith(
 | 
				
			||||||
            fontWeight: FontWeight.bold,
 | 
					            fontWeight: FontWeight.bold,
 | 
				
			||||||
 | 
					            color: Theme.of(context).colorScheme.onPrimary,
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        backgroundColor: Theme.of(context).colorScheme.primary,
 | 
					        backgroundColor: Theme.of(context).colorScheme.primary.withOpacity(0.8),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -94,7 +94,7 @@ class _LoginScreen extends BasedState<LoginScreen> {
 | 
				
			||||||
                Icon(
 | 
					                Icon(
 | 
				
			||||||
                  Icons.lock,
 | 
					                  Icons.lock,
 | 
				
			||||||
                  size: 100,
 | 
					                  size: 100,
 | 
				
			||||||
                  color: colorScheme.primary,
 | 
					                  color: colorScheme.primary.withOpacity(0.85),
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                FTextInput(
 | 
					                FTextInput(
 | 
				
			||||||
                  labelText: 'Username',
 | 
					                  labelText: 'Username',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,15 @@
 | 
				
			||||||
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/login.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/diary.dart';
 | 
					import 'package:fooder/widgets/diary.dart';
 | 
				
			||||||
 | 
					import 'package:fooder/widgets/summary.dart';
 | 
				
			||||||
import 'package:fooder/widgets/meal.dart';
 | 
					import 'package:fooder/widgets/meal.dart';
 | 
				
			||||||
import 'package:fooder/components/appBar.dart';
 | 
					import 'package:fooder/widgets/macroEntry.dart';
 | 
				
			||||||
import 'package:fooder/components/sliver.dart';
 | 
					import 'package:fooder/components/sliver.dart';
 | 
				
			||||||
import 'package:fooder/components/datePicker.dart';
 | 
					import 'package:fooder/components/datePicker.dart';
 | 
				
			||||||
 | 
					import 'package:blur/blur.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MainScreen extends BasedScreen {
 | 
					class MainScreen extends BasedScreen {
 | 
				
			||||||
  const MainScreen({super.key, required super.apiClient});
 | 
					  const MainScreen({super.key, required super.apiClient});
 | 
				
			||||||
| 
						 | 
					@ -43,16 +45,6 @@ class _MainScreen extends BasedState<MainScreen> {
 | 
				
			||||||
    await _asyncInitState();
 | 
					    await _asyncInitState();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void _logout() async {
 | 
					 | 
				
			||||||
    await widget.apiClient.logout();
 | 
					 | 
				
			||||||
    Navigator.pushReplacement(
 | 
					 | 
				
			||||||
      context,
 | 
					 | 
				
			||||||
      MaterialPageRoute(
 | 
					 | 
				
			||||||
        builder: (context) => LoginScreen(apiClient: widget.apiClient),
 | 
					 | 
				
			||||||
      ),
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Future<void> _addEntry() async {
 | 
					  Future<void> _addEntry() async {
 | 
				
			||||||
    await Navigator.push(
 | 
					    await Navigator.push(
 | 
				
			||||||
      context,
 | 
					      context,
 | 
				
			||||||
| 
						 | 
					@ -63,10 +55,65 @@ class _MainScreen extends BasedState<MainScreen> {
 | 
				
			||||||
    ).then((_) => _asyncInitState());
 | 
					    ).then((_) => _asyncInitState());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Widget floatingActionButton(BuildContext context) {
 | 
				
			||||||
 | 
					    var theme = Theme.of(context);
 | 
				
			||||||
 | 
					    var colorScheme = theme.colorScheme;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Container(
 | 
				
			||||||
 | 
					        height: 64,
 | 
				
			||||||
 | 
					        width: 64,
 | 
				
			||||||
 | 
					        decoration: BoxDecoration(
 | 
				
			||||||
 | 
					          borderRadius: BorderRadius.circular(32),
 | 
				
			||||||
 | 
					          boxShadow: [
 | 
				
			||||||
 | 
					            BoxShadow(
 | 
				
			||||||
 | 
					              color: colorScheme.primary.withOpacity(0.3),
 | 
				
			||||||
 | 
					              blurRadius: 5,
 | 
				
			||||||
 | 
					              offset: const Offset(0, 5),
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        child: ClipRRect(
 | 
				
			||||||
 | 
					          borderRadius: BorderRadius.circular(32),
 | 
				
			||||||
 | 
					          child: Stack(
 | 
				
			||||||
 | 
					            children: [
 | 
				
			||||||
 | 
					              Blur(
 | 
				
			||||||
 | 
					                blur: 10,
 | 
				
			||||||
 | 
					                blurColor: colorScheme.primary.withOpacity(0.1),
 | 
				
			||||||
 | 
					                child: Container(
 | 
				
			||||||
 | 
					                  height: 64,
 | 
				
			||||||
 | 
					                  width: 64,
 | 
				
			||||||
 | 
					                  decoration: BoxDecoration(
 | 
				
			||||||
 | 
					                    gradient: LinearGradient(
 | 
				
			||||||
 | 
					                      colors: [
 | 
				
			||||||
 | 
					                        colorScheme.primary.withOpacity(0.1),
 | 
				
			||||||
 | 
					                        colorScheme.secondary.withOpacity(0.1),
 | 
				
			||||||
 | 
					                      ],
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					              Container(
 | 
				
			||||||
 | 
					                height: 64,
 | 
				
			||||||
 | 
					                width: 64,
 | 
				
			||||||
 | 
					                child: FloatingActionButton(
 | 
				
			||||||
 | 
					                  elevation: 0,
 | 
				
			||||||
 | 
					                  onPressed: _addEntry,
 | 
				
			||||||
 | 
					                  backgroundColor: Colors.transparent,
 | 
				
			||||||
 | 
					                  child: Icon(
 | 
				
			||||||
 | 
					                    Icons.library_add,
 | 
				
			||||||
 | 
					                    color: colorScheme.onPrimary,
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    Widget content;
 | 
					    Widget content;
 | 
				
			||||||
    Widget title;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (diary != null) {
 | 
					    if (diary != null) {
 | 
				
			||||||
      content = CustomScrollView(
 | 
					      content = CustomScrollView(
 | 
				
			||||||
| 
						 | 
					@ -78,11 +125,17 @@ class _MainScreen extends BasedState<MainScreen> {
 | 
				
			||||||
          SliverList(
 | 
					          SliverList(
 | 
				
			||||||
            delegate: SliverChildListDelegate(
 | 
					            delegate: SliverChildListDelegate(
 | 
				
			||||||
              [
 | 
					              [
 | 
				
			||||||
                for (var meal in diary!.meals)
 | 
					                SummaryWidget(
 | 
				
			||||||
 | 
					                  diary: diary!,
 | 
				
			||||||
 | 
					                  apiClient: widget.apiClient,
 | 
				
			||||||
 | 
					                  refreshParent: _asyncInitState,
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                for (var (i, meal) in diary!.meals.indexed)
 | 
				
			||||||
                  MealWidget(
 | 
					                  MealWidget(
 | 
				
			||||||
                    meal: meal,
 | 
					                    meal: meal,
 | 
				
			||||||
                    apiClient: widget.apiClient,
 | 
					                    apiClient: widget.apiClient,
 | 
				
			||||||
                    refreshParent: _asyncInitState,
 | 
					                    refreshParent: _asyncInitState,
 | 
				
			||||||
 | 
					                    initiallyExpanded: i == 0,
 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
              ],
 | 
					              ],
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
| 
						 | 
					@ -93,14 +146,15 @@ class _MainScreen extends BasedState<MainScreen> {
 | 
				
			||||||
      content = const Center(child: const CircularProgressIndicator());
 | 
					      content = const Center(child: const CircularProgressIndicator());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return Scaffold(
 | 
					    return Scaffold(
 | 
				
			||||||
      body: content,
 | 
					      body: content,
 | 
				
			||||||
      extendBodyBehindAppBar: true,
 | 
					      extendBodyBehindAppBar: true,
 | 
				
			||||||
      appBar: FAppBar(),
 | 
					      extendBody: true,
 | 
				
			||||||
      floatingActionButton: FloatingActionButton(
 | 
					      appBar: appBar(),
 | 
				
			||||||
        onPressed: _addEntry,
 | 
					      bottomNavigationBar: navBar(),
 | 
				
			||||||
        child: const Icon(Icons.add),
 | 
					      floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
 | 
				
			||||||
      ),
 | 
					      floatingActionButton: floatingActionButton(context),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -77,7 +77,7 @@ class _RegisterScreen extends BasedState<RegisterScreen> {
 | 
				
			||||||
                Icon(
 | 
					                Icon(
 | 
				
			||||||
                  Icons.group_add,
 | 
					                  Icons.group_add,
 | 
				
			||||||
                  size: 100,
 | 
					                  size: 100,
 | 
				
			||||||
                  color: colorScheme.primary,
 | 
					                  color: colorScheme.primary.withOpacity(0.85),
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                FTextInput(
 | 
					                FTextInput(
 | 
				
			||||||
                  labelText: 'Username',
 | 
					                  labelText: 'Username',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -80,11 +80,12 @@ class DiaryWidget extends StatelessWidget {
 | 
				
			||||||
          SliverList(
 | 
					          SliverList(
 | 
				
			||||||
            delegate: SliverChildListDelegate(
 | 
					            delegate: SliverChildListDelegate(
 | 
				
			||||||
              [
 | 
					              [
 | 
				
			||||||
                for (var meal in diary.meals)
 | 
					                for (var (i, meal) in diary.meals.indexed)
 | 
				
			||||||
                  MealWidget(
 | 
					                  MealWidget(
 | 
				
			||||||
                    meal: meal,
 | 
					                    meal: meal,
 | 
				
			||||||
                    apiClient: apiClient,
 | 
					                    apiClient: apiClient,
 | 
				
			||||||
                    refreshParent: refreshParent,
 | 
					                    refreshParent: refreshParent,
 | 
				
			||||||
 | 
					                    initiallyExpanded: i == 0,
 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
              ],
 | 
					              ],
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,45 @@
 | 
				
			||||||
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/macro.dart';
 | 
					import 'package:fooder/widgets/macroEntry.dart';
 | 
				
			||||||
import 'dart:core';
 | 
					import 'dart:core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class EntryHeader extends StatelessWidget {
 | 
				
			||||||
 | 
					  final Entry entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const EntryHeader(
 | 
				
			||||||
 | 
					      {super.key,
 | 
				
			||||||
 | 
					      required this.entry});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    return Row(
 | 
				
			||||||
 | 
					      children: <Widget>[
 | 
				
			||||||
 | 
					        Padding(
 | 
				
			||||||
 | 
					          padding: const EdgeInsets.all(8),
 | 
				
			||||||
 | 
					          child: Text(
 | 
				
			||||||
 | 
					            entry.product.name,
 | 
				
			||||||
 | 
					            style: Theme.of(context).textTheme.bodyLarge!.copyWith(
 | 
				
			||||||
 | 
					              color: Theme.of(context).colorScheme.onPrimary,
 | 
				
			||||||
 | 
					              fontWeight: FontWeight.bold,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        Spacer(),
 | 
				
			||||||
 | 
					        Padding(
 | 
				
			||||||
 | 
					          padding: const EdgeInsets.all(8),
 | 
				
			||||||
 | 
					          child: Text(
 | 
				
			||||||
 | 
					            entry.grams.toStringAsFixed(0) + " g",
 | 
				
			||||||
 | 
					            style: Theme.of(context).textTheme.bodyText2!.copyWith(
 | 
				
			||||||
 | 
					              color: Theme.of(context).colorScheme.onPrimary,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class EntryWidget extends StatelessWidget {
 | 
					class EntryWidget extends StatelessWidget {
 | 
				
			||||||
  final Entry entry;
 | 
					  final Entry entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,25 +51,12 @@ class EntryWidget extends StatelessWidget {
 | 
				
			||||||
      padding: const EdgeInsets.all(8),
 | 
					      padding: const EdgeInsets.all(8),
 | 
				
			||||||
      child: Column(
 | 
					      child: Column(
 | 
				
			||||||
        children: <Widget>[
 | 
					        children: <Widget>[
 | 
				
			||||||
          Row(
 | 
					          EntryHeader(entry: entry),
 | 
				
			||||||
            children: <Widget>[
 | 
					          MacroEntryWidget(
 | 
				
			||||||
              Expanded(
 | 
					 | 
				
			||||||
                child: Text(
 | 
					 | 
				
			||||||
                  entry.product.name,
 | 
					 | 
				
			||||||
                  style: Theme.of(context).textTheme.titleLarge,
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
              ),
 | 
					 | 
				
			||||||
              Text("${entry.calories.toStringAsFixed(1)} kcal"),
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
          ),
 | 
					 | 
				
			||||||
          MacroWidget(
 | 
					 | 
				
			||||||
            protein: entry.protein,
 | 
					            protein: entry.protein,
 | 
				
			||||||
            carb: entry.carb,
 | 
					            carb: entry.carb,
 | 
				
			||||||
            fat: entry.fat,
 | 
					            fat: entry.fat,
 | 
				
			||||||
            amount: entry.grams,
 | 
					            calories: entry.calories,
 | 
				
			||||||
            style: Theme.of(context).textTheme.bodyMedium!.copyWith(
 | 
					 | 
				
			||||||
                  color: Theme.of(context).colorScheme.secondary,
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										156
									
								
								lib/widgets/macroEntry.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								lib/widgets/macroEntry.dart
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,156 @@
 | 
				
			||||||
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					import 'dart:core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MacroHeaderWidget extends StatelessWidget {
 | 
				
			||||||
 | 
					  static final double PAD_Y = 4;
 | 
				
			||||||
 | 
					  static final 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: EdgeInsets.symmetric(
 | 
				
			||||||
 | 
					            horizontal: 2,
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					          child: SizedBox(
 | 
				
			||||||
 | 
					            width: 55,
 | 
				
			||||||
 | 
					            child: Text(
 | 
				
			||||||
 | 
					              element,
 | 
				
			||||||
 | 
					              style: Theme.of(context).textTheme.bodyText1!.copyWith(
 | 
				
			||||||
 | 
					                color: Theme.of(context).colorScheme.onPrimary,
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					              textAlign: TextAlign.center,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    children.add(Spacer());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Padding(
 | 
				
			||||||
 | 
					      padding: EdgeInsets.symmetric(
 | 
				
			||||||
 | 
					        vertical: PAD_Y,
 | 
				
			||||||
 | 
					        horizontal: PAD_X,
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					      child: Row(
 | 
				
			||||||
 | 
					        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
 | 
				
			||||||
 | 
					        children: children,
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MacroEntryWidget extends StatelessWidget {
 | 
				
			||||||
 | 
					  static final double PAD_Y = 4;
 | 
				
			||||||
 | 
					  static final 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: EdgeInsets.symmetric(
 | 
				
			||||||
 | 
					            horizontal: 2,
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					          child: SizedBox(
 | 
				
			||||||
 | 
					            width: 55,
 | 
				
			||||||
 | 
					            child: Text(
 | 
				
			||||||
 | 
					              element,
 | 
				
			||||||
 | 
					              style: Theme.of(context).textTheme.bodyText1!.copyWith(
 | 
				
			||||||
 | 
					                color: Theme.of(context).colorScheme.onPrimary,
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					              textAlign: TextAlign.center,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    children.add(Spacer());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Padding(
 | 
				
			||||||
 | 
					      padding: EdgeInsets.symmetric(
 | 
				
			||||||
 | 
					        vertical: PAD_Y,
 | 
				
			||||||
 | 
					        horizontal: PAD_X,
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					      child: Row(
 | 
				
			||||||
 | 
					        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
 | 
				
			||||||
 | 
					        children: children,
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,93 +1,152 @@
 | 
				
			||||||
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/macro.dart';
 | 
					import 'package:fooder/widgets/macroEntry.dart';
 | 
				
			||||||
import 'package:fooder/screens/edit_entry.dart';
 | 
					import 'package:fooder/screens/edit_entry.dart';
 | 
				
			||||||
import 'package:fooder/screens/meal.dart';
 | 
					import 'package:fooder/screens/meal.dart';
 | 
				
			||||||
import 'package:fooder/client.dart';
 | 
					import 'package:fooder/client.dart';
 | 
				
			||||||
import 'dart:core';
 | 
					import 'dart:core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MealWidget extends StatelessWidget {
 | 
					 | 
				
			||||||
  final Meal meal;
 | 
					 | 
				
			||||||
  final ApiClient apiClient;
 | 
					 | 
				
			||||||
  final Function() refreshParent;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const MealWidget(
 | 
					class MealHeader extends StatelessWidget {
 | 
				
			||||||
 | 
					  final Meal meal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const MealHeader(
 | 
				
			||||||
      {super.key,
 | 
					      {super.key,
 | 
				
			||||||
      required this.meal,
 | 
					      required this.meal});
 | 
				
			||||||
      required this.apiClient,
 | 
					 | 
				
			||||||
      required this.refreshParent});
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    return Card(
 | 
					    return Row(
 | 
				
			||||||
        child: GestureDetector(
 | 
					      children: <Widget>[
 | 
				
			||||||
      onLongPress: () {
 | 
					        Padding(
 | 
				
			||||||
        Navigator.push(
 | 
					          padding: const EdgeInsets.all(8),
 | 
				
			||||||
          context,
 | 
					          child: Text(
 | 
				
			||||||
          MaterialPageRoute(
 | 
					            meal.name,
 | 
				
			||||||
            builder: (context) => MealScreen(
 | 
					            style: Theme.of(context).textTheme.headlineSmall!.copyWith(
 | 
				
			||||||
              apiClient: apiClient,
 | 
					              color: Theme.of(context).colorScheme.onPrimary,
 | 
				
			||||||
              meal: meal,
 | 
					              fontWeight: FontWeight.bold,
 | 
				
			||||||
              refresh: refreshParent,
 | 
					 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
        ).then((_) {
 | 
					 | 
				
			||||||
          refreshParent();
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      child: Padding(
 | 
					 | 
				
			||||||
        padding: const EdgeInsets.only(
 | 
					 | 
				
			||||||
            top: 36.0, left: 6.0, right: 6.0, bottom: 6.0),
 | 
					 | 
				
			||||||
        child: ExpansionTile(
 | 
					 | 
				
			||||||
          title: Column(
 | 
					 | 
				
			||||||
            children: <Widget>[
 | 
					 | 
				
			||||||
              Row(
 | 
					 | 
				
			||||||
                children: <Widget>[
 | 
					 | 
				
			||||||
                  Expanded(
 | 
					 | 
				
			||||||
                    child: Text(
 | 
					 | 
				
			||||||
                      meal.name,
 | 
					 | 
				
			||||||
                      style: Theme.of(context).textTheme.titleLarge?.copyWith(
 | 
					 | 
				
			||||||
                            color: Theme.of(context).colorScheme.primary,
 | 
					 | 
				
			||||||
                          ),
 | 
					 | 
				
			||||||
                    ),
 | 
					 | 
				
			||||||
                  ),
 | 
					 | 
				
			||||||
                  Text("${meal.calories.toStringAsFixed(1)} kcal"),
 | 
					 | 
				
			||||||
                ],
 | 
					 | 
				
			||||||
              ),
 | 
					 | 
				
			||||||
              MacroWidget(
 | 
					 | 
				
			||||||
                protein: meal.protein,
 | 
					 | 
				
			||||||
                carb: meal.carb,
 | 
					 | 
				
			||||||
                fat: meal.fat,
 | 
					 | 
				
			||||||
                style: Theme.of(context).textTheme.bodyMedium!.copyWith(
 | 
					 | 
				
			||||||
                      color: Theme.of(context).colorScheme.secondary,
 | 
					 | 
				
			||||||
                    ),
 | 
					 | 
				
			||||||
              ),
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
          ),
 | 
					 | 
				
			||||||
          children: <Widget>[
 | 
					 | 
				
			||||||
            for (var entry in meal.entries)
 | 
					 | 
				
			||||||
              ListTile(
 | 
					 | 
				
			||||||
                title: EntryWidget(
 | 
					 | 
				
			||||||
                  entry: entry,
 | 
					 | 
				
			||||||
                ),
 | 
					 | 
				
			||||||
                onTap: () {
 | 
					 | 
				
			||||||
                  Navigator.push(
 | 
					 | 
				
			||||||
                    context,
 | 
					 | 
				
			||||||
                    MaterialPageRoute(
 | 
					 | 
				
			||||||
                      builder: (context) => EditEntryScreen(
 | 
					 | 
				
			||||||
                        apiClient: apiClient,
 | 
					 | 
				
			||||||
                        entry: entry,
 | 
					 | 
				
			||||||
                      ),
 | 
					 | 
				
			||||||
                    ),
 | 
					 | 
				
			||||||
                  ).then((_) {
 | 
					 | 
				
			||||||
                    refreshParent();
 | 
					 | 
				
			||||||
                  });
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
              )
 | 
					 | 
				
			||||||
          ],
 | 
					 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
      ),
 | 
					      ],
 | 
				
			||||||
    ));
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MealWidget extends StatelessWidget {
 | 
				
			||||||
 | 
					  static final MAX_WIDTH = 920.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  final Meal meal;
 | 
				
			||||||
 | 
					  final ApiClient apiClient;
 | 
				
			||||||
 | 
					  final Function() refreshParent;
 | 
				
			||||||
 | 
					  final bool initiallyExpanded;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const MealWidget(
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      super.key,
 | 
				
			||||||
 | 
					      required this.meal,
 | 
				
			||||||
 | 
					      required this.apiClient,
 | 
				
			||||||
 | 
					      required this.refreshParent,
 | 
				
			||||||
 | 
					      required this.initiallyExpanded,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> _editMeal(context) async {
 | 
				
			||||||
 | 
					    await Navigator.push(
 | 
				
			||||||
 | 
					      context,
 | 
				
			||||||
 | 
					      MaterialPageRoute(
 | 
				
			||||||
 | 
					        builder: (context) => MealScreen(
 | 
				
			||||||
 | 
					          apiClient: apiClient,
 | 
				
			||||||
 | 
					          meal: meal,
 | 
				
			||||||
 | 
					          refresh: refreshParent,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    ).then((_) => refreshParent());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> _editEntry(context, entry) async {
 | 
				
			||||||
 | 
					    await Navigator.push(
 | 
				
			||||||
 | 
					      context,
 | 
				
			||||||
 | 
					      MaterialPageRoute(
 | 
				
			||||||
 | 
					        builder: (context) => EditEntryScreen(
 | 
				
			||||||
 | 
					          apiClient: apiClient,
 | 
				
			||||||
 | 
					          entry: entry,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    ).then((_) => refreshParent());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    var theme = Theme.of(context);
 | 
				
			||||||
 | 
					    var colorScheme = theme.colorScheme;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var width_avail = MediaQuery.of(context).size.width;
 | 
				
			||||||
 | 
					    var width = width_avail > MAX_WIDTH ? MAX_WIDTH : width_avail;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Center(
 | 
				
			||||||
 | 
					      child: Padding(
 | 
				
			||||||
 | 
					        padding: const EdgeInsets.all(8),
 | 
				
			||||||
 | 
					        child: Card(
 | 
				
			||||||
 | 
					          elevation: 4,
 | 
				
			||||||
 | 
					          clipBehavior: Clip.antiAlias,
 | 
				
			||||||
 | 
					          shadowColor: colorScheme.primary.withOpacity(1.0),
 | 
				
			||||||
 | 
					          shape: RoundedRectangleBorder(
 | 
				
			||||||
 | 
					            borderRadius: BorderRadius.circular(24),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					          child: SizedBox(
 | 
				
			||||||
 | 
					            width: width,
 | 
				
			||||||
 | 
					            child: Container(
 | 
				
			||||||
 | 
					              decoration: BoxDecoration(
 | 
				
			||||||
 | 
					                gradient: LinearGradient(
 | 
				
			||||||
 | 
					                  colors: [
 | 
				
			||||||
 | 
					                    colorScheme.primary.withOpacity(0.6),
 | 
				
			||||||
 | 
					                    colorScheme.secondary.withOpacity(0.5),
 | 
				
			||||||
 | 
					                  ],
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					              child: InkWell(
 | 
				
			||||||
 | 
					                splashColor: Colors.blue.withAlpha(30),
 | 
				
			||||||
 | 
					                onLongPress: () => _editMeal(context),
 | 
				
			||||||
 | 
					                child: ExpansionTile(
 | 
				
			||||||
 | 
					                  iconColor: colorScheme.onPrimary,
 | 
				
			||||||
 | 
					                  collapsedIconColor: colorScheme.onPrimary,
 | 
				
			||||||
 | 
					                  initiallyExpanded: initiallyExpanded,
 | 
				
			||||||
 | 
					                  title: Padding(
 | 
				
			||||||
 | 
					                    padding: const EdgeInsets.all(8),
 | 
				
			||||||
 | 
					                    child: Column(
 | 
				
			||||||
 | 
					                      children: <Widget>[
 | 
				
			||||||
 | 
					                        MealHeader(meal: meal),
 | 
				
			||||||
 | 
					                        MacroHeaderWidget(
 | 
				
			||||||
 | 
					                          calories: true,
 | 
				
			||||||
 | 
					                        ),
 | 
				
			||||||
 | 
					                        MacroEntryWidget(
 | 
				
			||||||
 | 
					                          protein: meal.protein,
 | 
				
			||||||
 | 
					                          carb: meal.carb,
 | 
				
			||||||
 | 
					                          fat: meal.fat,
 | 
				
			||||||
 | 
					                          calories: meal.calories,
 | 
				
			||||||
 | 
					                        ),
 | 
				
			||||||
 | 
					                      ],
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
 | 
					                  children: <Widget>[
 | 
				
			||||||
 | 
					                    for (var (i, entry) in meal.entries.indexed)
 | 
				
			||||||
 | 
					                      ListTile(
 | 
				
			||||||
 | 
					                        title: EntryWidget(
 | 
				
			||||||
 | 
					                          entry: entry,
 | 
				
			||||||
 | 
					                        ),
 | 
				
			||||||
 | 
					                        tileColor: i % 2 == 0 ? colorScheme.secondary.withOpacity(0.1): Colors.transparent,
 | 
				
			||||||
 | 
					                        onTap: () => _editEntry(context, entry),
 | 
				
			||||||
 | 
					                      )
 | 
				
			||||||
 | 
					                  ],
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										125
									
								
								lib/widgets/summary.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								lib/widgets/summary.dart
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,125 @@
 | 
				
			||||||
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					import 'package:fooder/models/diary.dart';
 | 
				
			||||||
 | 
					import 'package:fooder/widgets/macroEntry.dart';
 | 
				
			||||||
 | 
					import 'package:fooder/screens/add_meal.dart';
 | 
				
			||||||
 | 
					import 'package:fooder/client.dart';
 | 
				
			||||||
 | 
					import 'dart:core';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SummaryHeader extends StatelessWidget {
 | 
				
			||||||
 | 
					  final Diary diary;
 | 
				
			||||||
 | 
					  final Function addMeal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const SummaryHeader(
 | 
				
			||||||
 | 
					      {super.key,
 | 
				
			||||||
 | 
					      required this.addMeal,
 | 
				
			||||||
 | 
					      required this.diary});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    return Row(
 | 
				
			||||||
 | 
					      children: <Widget>[
 | 
				
			||||||
 | 
					        Padding(
 | 
				
			||||||
 | 
					          padding: const EdgeInsets.symmetric(horizontal: 8),
 | 
				
			||||||
 | 
					          child: Text(
 | 
				
			||||||
 | 
					            "Summary",
 | 
				
			||||||
 | 
					            style: Theme.of(context).textTheme.headlineSmall!.copyWith(
 | 
				
			||||||
 | 
					              color: Theme.of(context).colorScheme.onPrimary,
 | 
				
			||||||
 | 
					              fontWeight: FontWeight.bold,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        Spacer(),
 | 
				
			||||||
 | 
					        Padding(
 | 
				
			||||||
 | 
					          padding: const EdgeInsets.symmetric(horizontal: 8),
 | 
				
			||||||
 | 
					          child: IconButton(
 | 
				
			||||||
 | 
					            icon: Icon(Icons.playlist_add_rounded),
 | 
				
			||||||
 | 
					            iconSize: 32,
 | 
				
			||||||
 | 
					            color: Theme.of(context).colorScheme.onPrimary,
 | 
				
			||||||
 | 
					            onPressed: () => addMeal(context),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SummaryWidget extends StatelessWidget {
 | 
				
			||||||
 | 
					  static final MAX_WIDTH = 920.0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  final Diary diary;
 | 
				
			||||||
 | 
					  final ApiClient apiClient;
 | 
				
			||||||
 | 
					  final Function() refreshParent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const SummaryWidget(
 | 
				
			||||||
 | 
					      {super.key,
 | 
				
			||||||
 | 
					      required this.diary,
 | 
				
			||||||
 | 
					      required this.apiClient,
 | 
				
			||||||
 | 
					      required this.refreshParent});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> _addMeal(context) async {
 | 
				
			||||||
 | 
					    await Navigator.push(
 | 
				
			||||||
 | 
					      context,
 | 
				
			||||||
 | 
					      MaterialPageRoute(
 | 
				
			||||||
 | 
					        builder: (context) => AddMealScreen(
 | 
				
			||||||
 | 
					          apiClient: apiClient,
 | 
				
			||||||
 | 
					          diary: diary,
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    ).then((_) => refreshParent());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    var theme = Theme.of(context);
 | 
				
			||||||
 | 
					    var colorScheme = theme.colorScheme;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var width_avail = MediaQuery.of(context).size.width;
 | 
				
			||||||
 | 
					    var width = width_avail > MAX_WIDTH ? MAX_WIDTH : width_avail;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return Center(
 | 
				
			||||||
 | 
					      child: Padding(
 | 
				
			||||||
 | 
					        padding: const EdgeInsets.all(8),
 | 
				
			||||||
 | 
					        child: Card(
 | 
				
			||||||
 | 
					          elevation: 4,
 | 
				
			||||||
 | 
					          clipBehavior: Clip.antiAlias,
 | 
				
			||||||
 | 
					          shadowColor: colorScheme.primary.withOpacity(1.0),
 | 
				
			||||||
 | 
					          shape: RoundedRectangleBorder(
 | 
				
			||||||
 | 
					            borderRadius: BorderRadius.circular(24),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					          child: SizedBox(
 | 
				
			||||||
 | 
					            width: width,
 | 
				
			||||||
 | 
					            child: Container(
 | 
				
			||||||
 | 
					              decoration: BoxDecoration(
 | 
				
			||||||
 | 
					                gradient: LinearGradient(
 | 
				
			||||||
 | 
					                  colors: [
 | 
				
			||||||
 | 
					                    colorScheme.primary.withOpacity(0.6),
 | 
				
			||||||
 | 
					                    colorScheme.secondary.withOpacity(0.5),
 | 
				
			||||||
 | 
					                  ],
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					              child: Padding(
 | 
				
			||||||
 | 
					                padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 24),
 | 
				
			||||||
 | 
					                child: Column(
 | 
				
			||||||
 | 
					                  children: <Widget>[
 | 
				
			||||||
 | 
					                    SummaryHeader(diary: diary, addMeal: _addMeal),
 | 
				
			||||||
 | 
					                    MacroHeaderWidget(
 | 
				
			||||||
 | 
					                      calories: true,
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                    MacroEntryWidget(
 | 
				
			||||||
 | 
					                      protein: diary.protein,
 | 
				
			||||||
 | 
					                      carb: diary.carb,
 | 
				
			||||||
 | 
					                      fat: diary.fat,
 | 
				
			||||||
 | 
					                      calories: diary.calories,
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                  ],
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										26
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								pubspec.lock
									
									
									
									
									
								
							| 
						 | 
					@ -9,6 +9,14 @@ packages:
 | 
				
			||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "2.11.0"
 | 
					    version: "2.11.0"
 | 
				
			||||||
 | 
					  blur:
 | 
				
			||||||
 | 
					    dependency: "direct main"
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: blur
 | 
				
			||||||
 | 
					      sha256: fd23f1247faee4a7d1a3efb6b7c3cea134f3b939d72e5f8d45233deb0776259f
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "3.1.0"
 | 
				
			||||||
  boolean_selector:
 | 
					  boolean_selector:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
| 
						 | 
					@ -41,6 +49,14 @@ packages:
 | 
				
			||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "1.18.0"
 | 
					    version: "1.18.0"
 | 
				
			||||||
 | 
					  crypto:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: crypto
 | 
				
			||||||
 | 
					      sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "3.0.3"
 | 
				
			||||||
  cupertino_icons:
 | 
					  cupertino_icons:
 | 
				
			||||||
    dependency: "direct main"
 | 
					    dependency: "direct main"
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
| 
						 | 
					@ -168,6 +184,14 @@ packages:
 | 
				
			||||||
    description: flutter
 | 
					    description: flutter
 | 
				
			||||||
    source: sdk
 | 
					    source: sdk
 | 
				
			||||||
    version: "0.0.0"
 | 
					    version: "0.0.0"
 | 
				
			||||||
 | 
					  google_fonts:
 | 
				
			||||||
 | 
					    dependency: "direct main"
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: google_fonts
 | 
				
			||||||
 | 
					      sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "6.2.1"
 | 
				
			||||||
  http:
 | 
					  http:
 | 
				
			||||||
    dependency: "direct main"
 | 
					    dependency: "direct main"
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
| 
						 | 
					@ -495,4 +519,4 @@ packages:
 | 
				
			||||||
    version: "1.0.4"
 | 
					    version: "1.0.4"
 | 
				
			||||||
sdks:
 | 
					sdks:
 | 
				
			||||||
  dart: ">=3.3.0 <4.0.0"
 | 
					  dart: ">=3.3.0 <4.0.0"
 | 
				
			||||||
  flutter: ">=3.16.0"
 | 
					  flutter: ">=3.19.2"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,7 +39,9 @@ dependencies:
 | 
				
			||||||
  intl: ^0.19.0
 | 
					  intl: ^0.19.0
 | 
				
			||||||
  flutter_secure_storage: ^9.0.0
 | 
					  flutter_secure_storage: ^9.0.0
 | 
				
			||||||
  simple_barcode_scanner: ^0.1.1
 | 
					  simple_barcode_scanner: ^0.1.1
 | 
				
			||||||
 | 
					  google_fonts: ^6.2.1
 | 
				
			||||||
  flex_color_scheme: ^7.3.1
 | 
					  flex_color_scheme: ^7.3.1
 | 
				
			||||||
 | 
					  blur: ^3.1.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dev_dependencies:
 | 
					dev_dependencies:
 | 
				
			||||||
  flutter_test:
 | 
					  flutter_test:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue