[UI craze] linted
This commit is contained in:
parent
66b88f64fe
commit
ac803d3e71
22 changed files with 380 additions and 349 deletions
|
@ -5,13 +5,12 @@ import 'package:fooder/models/meal.dart';
|
||||||
|
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
|
|
||||||
|
|
||||||
class ApiClient {
|
class ApiClient {
|
||||||
final String baseUrl;
|
final String baseUrl;
|
||||||
String? token;
|
String? token;
|
||||||
String? refreshToken;
|
String? refreshToken;
|
||||||
http.Client httpClient = http.Client();
|
http.Client httpClient = http.Client();
|
||||||
final FlutterSecureStorage storage = FlutterSecureStorage();
|
final FlutterSecureStorage storage = const FlutterSecureStorage();
|
||||||
|
|
||||||
ApiClient({
|
ApiClient({
|
||||||
required this.baseUrl,
|
required this.baseUrl,
|
||||||
|
@ -219,8 +218,9 @@ class ApiClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>> getProductByBarcode(String barcode) async {
|
Future<Map<String, dynamic>> getProductByBarcode(String barcode) async {
|
||||||
var response =
|
var response = await get("/product/by_barcode?${Uri(queryParameters: {
|
||||||
await get("/product/by_barcode?${Uri(queryParameters: {"barcode": barcode}).query}");
|
"barcode": barcode
|
||||||
|
}).query}");
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,8 +283,7 @@ class ApiClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> addMeal(
|
Future<void> addMeal({required String name, required int diaryId}) async {
|
||||||
{required String name, required int diaryId}) async {
|
|
||||||
await post("/meal", {
|
await post("/meal", {
|
||||||
"name": name,
|
"name": name,
|
||||||
"diary_id": diaryId,
|
"diary_id": diaryId,
|
||||||
|
@ -292,7 +291,9 @@ class ApiClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> addMealFromPreset(
|
Future<void> addMealFromPreset(
|
||||||
{required String name, required int diaryId, required int presetId}) async {
|
{required String name,
|
||||||
|
required int diaryId,
|
||||||
|
required int presetId}) async {
|
||||||
await post("/meal/from_preset", {
|
await post("/meal/from_preset", {
|
||||||
"name": name,
|
"name": name,
|
||||||
"diary_id": diaryId,
|
"diary_id": diaryId,
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class FAppBar extends StatelessWidget implements PreferredSizeWidget {
|
|
||||||
final List<Widget> actions;
|
|
||||||
|
|
||||||
const FAppBar({super.key, required this.actions});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
var theme = Theme.of(context);
|
|
||||||
var colorScheme = theme.colorScheme;
|
|
||||||
|
|
||||||
return Padding(
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 8),
|
|
||||||
child: AppBar(
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
elevation: 0,
|
|
||||||
actions: actions,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Size get preferredSize => Size.fromHeight(56);
|
|
||||||
}
|
|
21
lib/components/app_bar.dart
Normal file
21
lib/components/app_bar.dart
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class FAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||||
|
final List<Widget> actions;
|
||||||
|
|
||||||
|
const FAppBar({super.key, required this.actions});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
|
child: AppBar(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
elevation: 0,
|
||||||
|
actions: actions,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Size get preferredSize => const Size.fromHeight(56);
|
||||||
|
}
|
|
@ -7,7 +7,13 @@ class FButton extends StatelessWidget {
|
||||||
final double fontSize;
|
final double fontSize;
|
||||||
final Function()? onPressed;
|
final Function()? onPressed;
|
||||||
|
|
||||||
const FButton({super.key, required this.labelText, this.padding = 8, this.insidePadding = 24, this.fontSize = 20, this.onPressed});
|
const FButton(
|
||||||
|
{super.key,
|
||||||
|
required this.labelText,
|
||||||
|
this.padding = 8,
|
||||||
|
this.insidePadding = 24,
|
||||||
|
this.fontSize = 20,
|
||||||
|
this.onPressed});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -15,38 +21,37 @@ class FButton extends StatelessWidget {
|
||||||
var colorScheme = theme.colorScheme;
|
var colorScheme = theme.colorScheme;
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: onPressed,
|
onTap: onPressed,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.symmetric(vertical: padding, horizontal: padding),
|
padding: EdgeInsets.symmetric(vertical: padding, horizontal: padding),
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.symmetric(vertical: insidePadding),
|
padding: EdgeInsets.symmetric(vertical: insidePadding),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: LinearGradient(
|
gradient: LinearGradient(
|
||||||
colors: [
|
colors: [
|
||||||
colorScheme.primary.withOpacity(0.5),
|
colorScheme.primary.withOpacity(0.5),
|
||||||
colorScheme.secondary.withOpacity(0.5),
|
colorScheme.secondary.withOpacity(0.5),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(4),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: colorScheme.primary.withOpacity(0.3),
|
||||||
|
blurRadius: 5,
|
||||||
|
offset: const Offset(0, 5),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
borderRadius: BorderRadius.circular(4),
|
child: Center(
|
||||||
boxShadow: [
|
child: Text(
|
||||||
BoxShadow(
|
labelText,
|
||||||
color: colorScheme.primary.withOpacity(0.3),
|
style: theme.textTheme.labelLarge!.copyWith(
|
||||||
blurRadius: 5,
|
fontWeight: FontWeight.bold,
|
||||||
offset: const Offset(0, 5),
|
fontSize: fontSize,
|
||||||
)
|
),
|
||||||
],
|
|
||||||
),
|
|
||||||
child: Center(
|
|
||||||
child: Text(
|
|
||||||
labelText,
|
|
||||||
style: theme.textTheme.button!.copyWith(
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: fontSize,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
));
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
||||||
class FDateItemWidget extends StatelessWidget {
|
class FDateItemWidget extends StatelessWidget {
|
||||||
final DateTime date;
|
final DateTime date;
|
||||||
final bool picked;
|
final bool picked;
|
||||||
final Function(DateTime) onDatePicked;
|
final Function(DateTime) onDatePicked;
|
||||||
|
|
||||||
const FDateItemWidget({super.key, required this.date, required this.onDatePicked, this.picked = false});
|
const FDateItemWidget(
|
||||||
|
{super.key,
|
||||||
|
required this.date,
|
||||||
|
required this.onDatePicked,
|
||||||
|
this.picked = false});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -28,7 +31,7 @@ class FDateItemWidget extends StatelessWidget {
|
||||||
onDatePicked(date);
|
onDatePicked(date);
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
width: picked? 100: 50,
|
width: picked ? 100 : 50,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(50),
|
borderRadius: BorderRadius.circular(50),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
|
@ -36,7 +39,9 @@ class FDateItemWidget extends StatelessWidget {
|
||||||
color: 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,
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
@ -45,7 +50,7 @@ class FDateItemWidget extends StatelessWidget {
|
||||||
dayOfTheWeekMap[date.weekday]!,
|
dayOfTheWeekMap[date.weekday]!,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: colorScheme.onPrimary,
|
color: colorScheme.onPrimary,
|
||||||
fontSize: picked ? 24: 12,
|
fontSize: picked ? 24 : 12,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -53,7 +58,7 @@ class FDateItemWidget extends StatelessWidget {
|
||||||
'${date.day}.${date.month}',
|
'${date.day}.${date.month}',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: colorScheme.onPrimary,
|
color: colorScheme.onPrimary,
|
||||||
fontSize: picked ? 24: 12,
|
fontSize: picked ? 24 : 12,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -68,7 +73,8 @@ class FDatePickerWidget extends StatefulWidget {
|
||||||
final DateTime date;
|
final DateTime date;
|
||||||
final Function(DateTime) onDatePicked;
|
final Function(DateTime) onDatePicked;
|
||||||
|
|
||||||
const FDatePickerWidget({super.key, required this.date, required this.onDatePicked});
|
const FDatePickerWidget(
|
||||||
|
{super.key, required this.date, required this.onDatePicked});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<FDatePickerWidget> createState() => _FDatePickerWidgetState();
|
State<FDatePickerWidget> createState() => _FDatePickerWidgetState();
|
||||||
|
@ -106,13 +112,18 @@ class _FDatePickerWidgetState extends State<FDatePickerWidget> {
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
FDateItemWidget(date: date.add(Duration(days: -3)), onDatePicked: onDatePicked),
|
FDateItemWidget(
|
||||||
FDateItemWidget(date: date.add(Duration(days: -2)), onDatePicked: onDatePicked),
|
date: date.add(const Duration(days: -2)),
|
||||||
FDateItemWidget(date: date.add(Duration(days: -1)), onDatePicked: onDatePicked),
|
onDatePicked: onDatePicked),
|
||||||
FDateItemWidget(date: date, onDatePicked: onDatePicked, picked: true),
|
FDateItemWidget(
|
||||||
FDateItemWidget(date: date.add(Duration(days: 1)), onDatePicked: onDatePicked),
|
date: date.add(const Duration(days: -1)),
|
||||||
FDateItemWidget(date: date.add(Duration(days: 2)), onDatePicked: onDatePicked),
|
onDatePicked: onDatePicked),
|
||||||
Container(
|
FDateItemWidget(
|
||||||
|
date: date, onDatePicked: onDatePicked, picked: true),
|
||||||
|
FDateItemWidget(
|
||||||
|
date: date.add(const Duration(days: 1)),
|
||||||
|
onDatePicked: onDatePicked),
|
||||||
|
SizedBox(
|
||||||
width: 50,
|
width: 50,
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
|
@ -125,8 +136,8 @@ class _FDatePickerWidgetState extends State<FDatePickerWidget> {
|
||||||
showDatePicker(
|
showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
initialDate: date,
|
initialDate: date,
|
||||||
firstDate: date.add(Duration(days: -365)),
|
firstDate: date.add(const Duration(days: -365)),
|
||||||
lastDate: date.add(Duration(days: 365)),
|
lastDate: date.add(const Duration(days: 365)),
|
||||||
).then((value) {
|
).then((value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
onDatePicked(value);
|
onDatePicked(value);
|
|
@ -1,64 +0,0 @@
|
||||||
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,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
68
lib/components/navigation_bar.dart
Normal file
68
lib/components/navigation_bar.dart
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:blur/blur.dart';
|
||||||
|
|
||||||
|
class FNavBar extends StatelessWidget {
|
||||||
|
static const maxWidth = 920.0;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
var widthAvail = MediaQuery.of(context).size.width;
|
||||||
|
// var width = widthAvail > maxWidth ? maxWidth : widthAvail;
|
||||||
|
|
||||||
|
return SafeArea(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(24),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: colorScheme.primary.withOpacity(0.3),
|
||||||
|
blurRadius: 5,
|
||||||
|
offset: const Offset(0, 5),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
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,13 +1,13 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:blur/blur.dart';
|
import 'package:blur/blur.dart';
|
||||||
|
|
||||||
|
|
||||||
class ClipShadowPath extends StatelessWidget {
|
class ClipShadowPath extends StatelessWidget {
|
||||||
final Shadow shadow;
|
final Shadow shadow;
|
||||||
final CustomClipper<Path> clipper;
|
final CustomClipper<Path> clipper;
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|
||||||
ClipShadowPath({
|
const ClipShadowPath({
|
||||||
|
super.key,
|
||||||
required this.shadow,
|
required this.shadow,
|
||||||
required this.clipper,
|
required this.clipper,
|
||||||
required this.child,
|
required this.child,
|
||||||
|
@ -17,10 +17,10 @@ class ClipShadowPath extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return CustomPaint(
|
return CustomPaint(
|
||||||
painter: _ClipShadowShadowPainter(
|
painter: _ClipShadowShadowPainter(
|
||||||
clipper: this.clipper,
|
clipper: clipper,
|
||||||
shadow: this.shadow,
|
shadow: shadow,
|
||||||
),
|
),
|
||||||
child: ClipPath(child: child, clipper: this.clipper),
|
child: ClipPath(clipper: clipper, child: child),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ class _ClipShadowShadowPainter extends CustomPainter {
|
||||||
class BackgroundWave extends StatelessWidget {
|
class BackgroundWave extends StatelessWidget {
|
||||||
final double height;
|
final double height;
|
||||||
|
|
||||||
const BackgroundWave({Key? key, required this.height}) : super(key: key);
|
const BackgroundWave({super.key, required this.height});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -94,21 +94,30 @@ class BackgroundWaveClipper extends CustomClipper<Path> {
|
||||||
var lastCurve = Offset(40, 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 - 40, 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,
|
||||||
);
|
);
|
||||||
|
|
||||||
firstCurve = Offset(size.width, size.height - 20);
|
firstCurve = Offset(size.width, size.height - 20);
|
||||||
lastCurve = Offset(size.width, size.height);
|
lastCurve = Offset(size.width, size.height);
|
||||||
|
|
||||||
path.quadraticBezierTo(
|
path.quadraticBezierTo(
|
||||||
firstCurve.dx, firstCurve.dy, lastCurve.dx, lastCurve.dy,
|
firstCurve.dx,
|
||||||
|
firstCurve.dy,
|
||||||
|
lastCurve.dx,
|
||||||
|
lastCurve.dy,
|
||||||
);
|
);
|
||||||
|
|
||||||
path.lineTo(size.width, 0.0);
|
path.lineTo(size.width, 0.0);
|
||||||
|
@ -126,8 +135,10 @@ class FSliverAppBar extends SliverPersistentHeaderDelegate {
|
||||||
const FSliverAppBar({required this.child});
|
const FSliverAppBar({required this.child});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
|
Widget build(
|
||||||
var adjustedShrinkOffset = shrinkOffset > minExtent ? minExtent : shrinkOffset;
|
BuildContext context, double shrinkOffset, bool overlapsContent) {
|
||||||
|
var adjustedShrinkOffset =
|
||||||
|
shrinkOffset > minExtent ? minExtent : shrinkOffset;
|
||||||
double offset = (minExtent - adjustedShrinkOffset);
|
double offset = (minExtent - adjustedShrinkOffset);
|
||||||
|
|
||||||
if (offset < 4) {
|
if (offset < 4) {
|
||||||
|
@ -141,9 +152,9 @@ class FSliverAppBar extends SliverPersistentHeaderDelegate {
|
||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
top: offset,
|
top: offset,
|
||||||
child: child,
|
|
||||||
left: 16,
|
left: 16,
|
||||||
right: 16,
|
right: 16,
|
||||||
|
child: child,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,7 +9,15 @@ class FTextInput extends StatelessWidget {
|
||||||
final bool obscureText;
|
final bool obscureText;
|
||||||
final Function(String)? onFieldSubmitted;
|
final Function(String)? onFieldSubmitted;
|
||||||
|
|
||||||
const FTextInput({super.key, required this.labelText, this.padding = 8, required this.controller, this.autofillHints, this.autofocus = false, this.onFieldSubmitted, this.obscureText = false});
|
const FTextInput(
|
||||||
|
{super.key,
|
||||||
|
required this.labelText,
|
||||||
|
this.padding = 8,
|
||||||
|
required this.controller,
|
||||||
|
this.autofillHints,
|
||||||
|
this.autofocus = false,
|
||||||
|
this.onFieldSubmitted,
|
||||||
|
this.obscureText = false});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
|
@ -7,8 +7,6 @@ import 'package:fooder/models/meal.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:simple_barcode_scanner/simple_barcode_scanner.dart';
|
import 'package:simple_barcode_scanner/simple_barcode_scanner.dart';
|
||||||
import 'package:fooder/components/appBar.dart';
|
|
||||||
|
|
||||||
|
|
||||||
class AddEntryScreen extends BasedScreen {
|
class AddEntryScreen extends BasedScreen {
|
||||||
final Diary diary;
|
final Diary diary;
|
||||||
|
@ -58,6 +56,7 @@ class _AddEntryScreen extends BasedState<AddEntryScreen> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
void showError(String message) {
|
void showError(String message) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
|
@ -99,7 +98,6 @@ class _AddEntryScreen extends BasedState<AddEntryScreen> {
|
||||||
popMeDaddy();
|
popMeDaddy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Future<void> _findProductByBarCode() async {
|
Future<void> _findProductByBarCode() async {
|
||||||
var res = await Navigator.push(
|
var res = await Navigator.push(
|
||||||
context,
|
context,
|
||||||
|
@ -110,8 +108,7 @@ class _AddEntryScreen extends BasedState<AddEntryScreen> {
|
||||||
|
|
||||||
if (res is String) {
|
if (res is String) {
|
||||||
try {
|
try {
|
||||||
var productMap =
|
var productMap = await widget.apiClient.getProductByBarcode(res);
|
||||||
await widget.apiClient.getProductByBarcode(res);
|
|
||||||
|
|
||||||
var product = Product.fromJson(productMap);
|
var product = Product.fromJson(productMap);
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,8 @@ class _AddProductScreen extends State<AddProductScreen> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<double?> _parseDouble(String text, String name, {bool silent = false}) async {
|
Future<double?> _parseDouble(String text, String name,
|
||||||
|
{bool silent = false}) async {
|
||||||
try {
|
try {
|
||||||
return double.parse(text.replaceAll(",", "."));
|
return double.parse(text.replaceAll(",", "."));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -58,7 +59,8 @@ class _AddProductScreen extends State<AddProductScreen> {
|
||||||
var carb = await _parseDouble(carbController.text, "Carbs");
|
var carb = await _parseDouble(carbController.text, "Carbs");
|
||||||
var fat = await _parseDouble(fatController.text, "Fat");
|
var fat = await _parseDouble(fatController.text, "Fat");
|
||||||
var protein = await _parseDouble(proteinController.text, "Protein");
|
var protein = await _parseDouble(proteinController.text, "Protein");
|
||||||
var fiber = await _parseDouble(fiberController.text, "Fiber", silent: true) ?? 0;
|
var fiber =
|
||||||
|
await _parseDouble(fiberController.text, "Fiber", silent: true) ?? 0;
|
||||||
|
|
||||||
if (carb == null || fat == null || protein == null) {
|
if (carb == null || fat == null || protein == null) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
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/app_bar.dart';
|
||||||
import 'package:fooder/components/navigationBar.dart';
|
import 'package:fooder/components/navigation_bar.dart';
|
||||||
import 'package:fooder/screens/login.dart';
|
import 'package:fooder/screens/login.dart';
|
||||||
import 'package:fooder/screens/main.dart';
|
import 'package:fooder/screens/main.dart';
|
||||||
|
|
||||||
|
@ -69,21 +69,21 @@ abstract class BasedState<T extends BasedScreen> extends State<T> {
|
||||||
Icons.dinner_dining,
|
Icons.dinner_dining,
|
||||||
color: Theme.of(context).colorScheme.onPrimary,
|
color: Theme.of(context).colorScheme.onPrimary,
|
||||||
),
|
),
|
||||||
onPressed: () => null,
|
onPressed: () {},
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.lunch_dining,
|
Icons.lunch_dining,
|
||||||
color: Theme.of(context).colorScheme.onPrimary,
|
color: Theme.of(context).colorScheme.onPrimary,
|
||||||
),
|
),
|
||||||
onPressed: () => null,
|
onPressed: () {},
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.person,
|
Icons.person,
|
||||||
color: Theme.of(context).colorScheme.onPrimary,
|
color: Theme.of(context).colorScheme.onPrimary,
|
||||||
),
|
),
|
||||||
onPressed: () => null,
|
onPressed: () {},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -98,9 +98,9 @@ abstract class BasedState<T extends BasedScreen> extends State<T> {
|
||||||
message,
|
message,
|
||||||
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,
|
color: Theme.of(context).colorScheme.onError,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
backgroundColor: Theme.of(context).colorScheme.error.withOpacity(0.8),
|
backgroundColor: Theme.of(context).colorScheme.error.withOpacity(0.8),
|
||||||
),
|
),
|
||||||
|
@ -114,9 +114,9 @@ abstract class BasedState<T extends BasedScreen> extends State<T> {
|
||||||
text,
|
text,
|
||||||
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,
|
color: Theme.of(context).colorScheme.onPrimary,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
backgroundColor: Theme.of(context).colorScheme.primary.withOpacity(0.8),
|
backgroundColor: Theme.of(context).colorScheme.primary.withOpacity(0.8),
|
||||||
),
|
),
|
||||||
|
|
|
@ -106,8 +106,7 @@ class _EditEntryScreen extends State<EditEntryScreen> {
|
||||||
|
|
||||||
if (res is String) {
|
if (res is String) {
|
||||||
try {
|
try {
|
||||||
var productMap =
|
var productMap = await widget.apiClient.getProductByBarcode(res);
|
||||||
await widget.apiClient.getProductByBarcode(res);
|
|
||||||
|
|
||||||
var product = Product.fromJson(productMap);
|
var product = Product.fromJson(productMap);
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
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/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/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/date_picker.dart';
|
||||||
import 'package:blur/blur.dart';
|
import 'package:blur/blur.dart';
|
||||||
|
|
||||||
class MainScreen extends BasedScreen {
|
class MainScreen extends BasedScreen {
|
||||||
|
@ -60,54 +57,54 @@ class _MainScreen extends BasedState<MainScreen> {
|
||||||
var colorScheme = theme.colorScheme;
|
var colorScheme = theme.colorScheme;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
height: 64,
|
height: 64,
|
||||||
width: 64,
|
width: 64,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(32),
|
borderRadius: BorderRadius.circular(32),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: colorScheme.primary.withOpacity(0.3),
|
color: colorScheme.primary.withOpacity(0.3),
|
||||||
blurRadius: 5,
|
blurRadius: 5,
|
||||||
offset: const Offset(0, 5),
|
offset: const Offset(0, 5),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(32),
|
borderRadius: BorderRadius.circular(32),
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
Blur(
|
Blur(
|
||||||
blur: 10,
|
blur: 10,
|
||||||
blurColor: colorScheme.primary.withOpacity(0.1),
|
blurColor: colorScheme.primary.withOpacity(0.1),
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 64,
|
|
||||||
width: 64,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
gradient: LinearGradient(
|
|
||||||
colors: [
|
|
||||||
colorScheme.primary.withOpacity(0.1),
|
|
||||||
colorScheme.secondary.withOpacity(0.1),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
height: 64,
|
height: 64,
|
||||||
width: 64,
|
width: 64,
|
||||||
child: FloatingActionButton(
|
decoration: BoxDecoration(
|
||||||
elevation: 0,
|
gradient: LinearGradient(
|
||||||
onPressed: _addEntry,
|
colors: [
|
||||||
backgroundColor: Colors.transparent,
|
colorScheme.primary.withOpacity(0.1),
|
||||||
child: Icon(
|
colorScheme.secondary.withOpacity(0.1),
|
||||||
Icons.library_add,
|
],
|
||||||
color: colorScheme.onPrimary,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
SizedBox(
|
||||||
|
height: 64,
|
||||||
|
width: 64,
|
||||||
|
child: FloatingActionButton(
|
||||||
|
elevation: 0,
|
||||||
|
onPressed: _addEntry,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
child: Icon(
|
||||||
|
Icons.library_add,
|
||||||
|
color: colorScheme.onPrimary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,37 +113,35 @@ class _MainScreen extends BasedState<MainScreen> {
|
||||||
Widget content;
|
Widget content;
|
||||||
|
|
||||||
if (diary != null) {
|
if (diary != null) {
|
||||||
content = CustomScrollView(
|
content = CustomScrollView(slivers: <Widget>[
|
||||||
slivers: <Widget>[
|
SliverPersistentHeader(
|
||||||
SliverPersistentHeader(
|
delegate: FSliverAppBar(
|
||||||
delegate: FSliverAppBar(child: FDatePickerWidget(date: date, onDatePicked: _pickDate)),
|
child: FDatePickerWidget(date: date, onDatePicked: _pickDate)),
|
||||||
pinned: true,
|
pinned: true,
|
||||||
),
|
),
|
||||||
SliverList(
|
SliverList(
|
||||||
delegate: SliverChildListDelegate(
|
delegate: SliverChildListDelegate(
|
||||||
[
|
[
|
||||||
SummaryWidget(
|
SummaryWidget(
|
||||||
diary: diary!,
|
diary: diary!,
|
||||||
|
apiClient: widget.apiClient,
|
||||||
|
refreshParent: _asyncInitState,
|
||||||
|
),
|
||||||
|
for (var (i, meal) in diary!.meals.indexed)
|
||||||
|
MealWidget(
|
||||||
|
meal: meal,
|
||||||
apiClient: widget.apiClient,
|
apiClient: widget.apiClient,
|
||||||
refreshParent: _asyncInitState,
|
refreshParent: _asyncInitState,
|
||||||
|
initiallyExpanded: i == 0,
|
||||||
),
|
),
|
||||||
for (var (i, meal) in diary!.meals.indexed)
|
],
|
||||||
MealWidget(
|
|
||||||
meal: meal,
|
|
||||||
apiClient: widget.apiClient,
|
|
||||||
refreshParent: _asyncInitState,
|
|
||||||
initiallyExpanded: i == 0,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
]
|
),
|
||||||
);
|
]);
|
||||||
} else {
|
} else {
|
||||||
content = const Center(child: const CircularProgressIndicator());
|
content = const Center(child: CircularProgressIndicator());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: content,
|
body: content,
|
||||||
extendBodyBehindAppBar: true,
|
extendBodyBehindAppBar: true,
|
||||||
|
|
|
@ -7,7 +7,11 @@ class MealScreen extends BasedScreen {
|
||||||
final Meal meal;
|
final Meal meal;
|
||||||
final Function() refresh;
|
final Function() refresh;
|
||||||
|
|
||||||
const MealScreen({super.key, required super.apiClient, required this.refresh, required this.meal});
|
const MealScreen(
|
||||||
|
{super.key,
|
||||||
|
required super.apiClient,
|
||||||
|
required this.refresh,
|
||||||
|
required this.meal});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<MealScreen> createState() => _AddMealScreen();
|
State<MealScreen> createState() => _AddMealScreen();
|
||||||
|
|
|
@ -3,13 +3,10 @@ import 'package:fooder/models/entry.dart';
|
||||||
import 'package:fooder/widgets/macroEntry.dart';
|
import 'package:fooder/widgets/macroEntry.dart';
|
||||||
import 'dart:core';
|
import 'dart:core';
|
||||||
|
|
||||||
|
|
||||||
class EntryHeader extends StatelessWidget {
|
class EntryHeader extends StatelessWidget {
|
||||||
final Entry entry;
|
final Entry entry;
|
||||||
|
|
||||||
const EntryHeader(
|
const EntryHeader({super.key, required this.entry});
|
||||||
{super.key,
|
|
||||||
required this.entry});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -20,19 +17,19 @@ class EntryHeader extends StatelessWidget {
|
||||||
child: Text(
|
child: Text(
|
||||||
entry.product.name,
|
entry.product.name,
|
||||||
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
|
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
|
||||||
color: Theme.of(context).colorScheme.onPrimary,
|
color: Theme.of(context).colorScheme.onPrimary,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Spacer(),
|
const Spacer(),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: Text(
|
child: Text(
|
||||||
entry.grams.toStringAsFixed(0) + " g",
|
"${entry.grams.toStringAsFixed(0)} g",
|
||||||
style: Theme.of(context).textTheme.bodyText2!.copyWith(
|
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||||
color: Theme.of(context).colorScheme.onPrimary,
|
color: Theme.of(context).colorScheme.onPrimary,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
@ -11,7 +11,7 @@ class MacroWidget extends StatelessWidget {
|
||||||
final Widget? child;
|
final Widget? child;
|
||||||
|
|
||||||
const MacroWidget({
|
const MacroWidget({
|
||||||
Key? key,
|
super.key,
|
||||||
this.calories,
|
this.calories,
|
||||||
this.amount,
|
this.amount,
|
||||||
this.child,
|
this.child,
|
||||||
|
@ -20,7 +20,7 @@ class MacroWidget extends StatelessWidget {
|
||||||
required this.carb,
|
required this.carb,
|
||||||
required this.fat,
|
required this.fat,
|
||||||
required this.style,
|
required this.style,
|
||||||
}) : super(key: key);
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
|
@ -1,22 +1,18 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'dart:core';
|
import 'dart:core';
|
||||||
|
|
||||||
|
|
||||||
class MacroHeaderWidget extends StatelessWidget {
|
class MacroHeaderWidget extends StatelessWidget {
|
||||||
static final double PAD_Y = 4;
|
static const double PAD_Y = 4;
|
||||||
static final double PAD_X = 8;
|
static const double PAD_X = 8;
|
||||||
|
|
||||||
final bool? fiber;
|
final bool? fiber;
|
||||||
final bool? calories;
|
final bool? calories;
|
||||||
|
|
||||||
const MacroHeaderWidget(
|
const MacroHeaderWidget({
|
||||||
{
|
super.key,
|
||||||
super.key,
|
this.fiber = false,
|
||||||
this.fiber = false,
|
this.calories = false,
|
||||||
this.calories = false,
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -43,16 +39,16 @@ class MacroHeaderWidget extends StatelessWidget {
|
||||||
for (var element in elements) {
|
for (var element in elements) {
|
||||||
children.add(
|
children.add(
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 2,
|
horizontal: 2,
|
||||||
),
|
),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 55,
|
width: 55,
|
||||||
child: Text(
|
child: Text(
|
||||||
element,
|
element,
|
||||||
style: Theme.of(context).textTheme.bodyText1!.copyWith(
|
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
|
||||||
color: Theme.of(context).colorScheme.onPrimary,
|
color: Theme.of(context).colorScheme.onPrimary,
|
||||||
),
|
),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -60,10 +56,10 @@ class MacroHeaderWidget extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
children.add(Spacer());
|
children.add(const Spacer());
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
vertical: PAD_Y,
|
vertical: PAD_Y,
|
||||||
horizontal: PAD_X,
|
horizontal: PAD_X,
|
||||||
),
|
),
|
||||||
|
@ -75,10 +71,9 @@ class MacroHeaderWidget extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class MacroEntryWidget extends StatelessWidget {
|
class MacroEntryWidget extends StatelessWidget {
|
||||||
static final double PAD_Y = 4;
|
static const double PAD_Y = 4;
|
||||||
static final double PAD_X = 8;
|
static const double PAD_X = 8;
|
||||||
|
|
||||||
final double protein;
|
final double protein;
|
||||||
final double carb;
|
final double carb;
|
||||||
|
@ -86,35 +81,32 @@ class MacroEntryWidget extends StatelessWidget {
|
||||||
final double? fiber;
|
final double? fiber;
|
||||||
final double? calories;
|
final double? calories;
|
||||||
|
|
||||||
const MacroEntryWidget(
|
const MacroEntryWidget({
|
||||||
{
|
super.key,
|
||||||
super.key,
|
required this.protein,
|
||||||
required this.protein,
|
required this.carb,
|
||||||
required this.carb,
|
required this.fat,
|
||||||
required this.fat,
|
this.fiber,
|
||||||
this.fiber,
|
this.calories,
|
||||||
this.calories,
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var elements = <String>[
|
var elements = <String>[
|
||||||
"${carb.toStringAsFixed(1)}",
|
(carb.toStringAsFixed(1)),
|
||||||
"${fat.toStringAsFixed(1)}",
|
(fat.toStringAsFixed(1)),
|
||||||
"${protein.toStringAsFixed(1)}",
|
(protein.toStringAsFixed(1)),
|
||||||
];
|
];
|
||||||
|
|
||||||
if (fiber != null) {
|
if (fiber != null) {
|
||||||
elements.add(
|
elements.add(
|
||||||
"${fiber!.toStringAsFixed(1)}",
|
fiber!.toStringAsFixed(1),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (calories != null) {
|
if (calories != null) {
|
||||||
elements.add(
|
elements.add(
|
||||||
"${calories!.toStringAsFixed(0)}",
|
calories!.toStringAsFixed(0),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,16 +115,16 @@ class MacroEntryWidget extends StatelessWidget {
|
||||||
for (var element in elements) {
|
for (var element in elements) {
|
||||||
children.add(
|
children.add(
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 2,
|
horizontal: 2,
|
||||||
),
|
),
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 55,
|
width: 55,
|
||||||
child: Text(
|
child: Text(
|
||||||
element,
|
element,
|
||||||
style: Theme.of(context).textTheme.bodyText1!.copyWith(
|
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
|
||||||
color: Theme.of(context).colorScheme.onPrimary,
|
color: Theme.of(context).colorScheme.onPrimary,
|
||||||
),
|
),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -140,10 +132,10 @@ class MacroEntryWidget extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
children.add(Spacer());
|
children.add(const Spacer());
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
vertical: PAD_Y,
|
vertical: PAD_Y,
|
||||||
horizontal: PAD_X,
|
horizontal: PAD_X,
|
||||||
),
|
),
|
||||||
|
|
|
@ -7,13 +7,10 @@ import 'package:fooder/screens/meal.dart';
|
||||||
import 'package:fooder/client.dart';
|
import 'package:fooder/client.dart';
|
||||||
import 'dart:core';
|
import 'dart:core';
|
||||||
|
|
||||||
|
|
||||||
class MealHeader extends StatelessWidget {
|
class MealHeader extends StatelessWidget {
|
||||||
final Meal meal;
|
final Meal meal;
|
||||||
|
|
||||||
const MealHeader(
|
const MealHeader({super.key, required this.meal});
|
||||||
{super.key,
|
|
||||||
required this.meal});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -24,9 +21,9 @@ class MealHeader extends StatelessWidget {
|
||||||
child: Text(
|
child: Text(
|
||||||
meal.name,
|
meal.name,
|
||||||
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.onPrimary,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -34,24 +31,21 @@ class MealHeader extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class MealWidget extends StatelessWidget {
|
class MealWidget extends StatelessWidget {
|
||||||
static final MAX_WIDTH = 920.0;
|
static const maxWidth = 920.0;
|
||||||
|
|
||||||
final Meal meal;
|
final Meal meal;
|
||||||
final ApiClient apiClient;
|
final ApiClient apiClient;
|
||||||
final Function() refreshParent;
|
final Function() refreshParent;
|
||||||
final bool initiallyExpanded;
|
final bool initiallyExpanded;
|
||||||
|
|
||||||
const MealWidget(
|
const MealWidget({
|
||||||
{
|
super.key,
|
||||||
super.key,
|
required this.meal,
|
||||||
required this.meal,
|
required this.apiClient,
|
||||||
required this.apiClient,
|
required this.refreshParent,
|
||||||
required this.refreshParent,
|
required this.initiallyExpanded,
|
||||||
required this.initiallyExpanded,
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
Future<void> _editMeal(context) async {
|
Future<void> _editMeal(context) async {
|
||||||
await Navigator.push(
|
await Navigator.push(
|
||||||
|
@ -83,8 +77,8 @@ class MealWidget extends StatelessWidget {
|
||||||
var theme = Theme.of(context);
|
var theme = Theme.of(context);
|
||||||
var colorScheme = theme.colorScheme;
|
var colorScheme = theme.colorScheme;
|
||||||
|
|
||||||
var width_avail = MediaQuery.of(context).size.width;
|
var widthAvail = MediaQuery.of(context).size.width;
|
||||||
var width = width_avail > MAX_WIDTH ? MAX_WIDTH : width_avail;
|
var width = widthAvail > maxWidth ? maxWidth : widthAvail;
|
||||||
|
|
||||||
return Center(
|
return Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
@ -119,7 +113,7 @@ class MealWidget extends StatelessWidget {
|
||||||
child: Column(
|
child: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
MealHeader(meal: meal),
|
MealHeader(meal: meal),
|
||||||
MacroHeaderWidget(
|
const MacroHeaderWidget(
|
||||||
calories: true,
|
calories: true,
|
||||||
),
|
),
|
||||||
MacroEntryWidget(
|
MacroEntryWidget(
|
||||||
|
@ -137,7 +131,9 @@ class MealWidget extends StatelessWidget {
|
||||||
title: EntryWidget(
|
title: EntryWidget(
|
||||||
entry: entry,
|
entry: entry,
|
||||||
),
|
),
|
||||||
tileColor: i % 2 == 0 ? colorScheme.secondary.withOpacity(0.1): Colors.transparent,
|
tileColor: i % 2 == 0
|
||||||
|
? colorScheme.secondary.withOpacity(0.1)
|
||||||
|
: Colors.transparent,
|
||||||
onTap: () => _editEntry(context, entry),
|
onTap: () => _editEntry(context, entry),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|
|
@ -5,15 +5,11 @@ 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;
|
final Function addMeal;
|
||||||
|
|
||||||
const SummaryHeader(
|
const SummaryHeader({super.key, required this.addMeal, required this.diary});
|
||||||
{super.key,
|
|
||||||
required this.addMeal,
|
|
||||||
required this.diary});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -24,16 +20,16 @@ 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.onPrimary,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Spacer(),
|
const Spacer(),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: Icon(Icons.playlist_add_rounded),
|
icon: const Icon(Icons.playlist_add_rounded),
|
||||||
iconSize: 32,
|
iconSize: 32,
|
||||||
color: Theme.of(context).colorScheme.onPrimary,
|
color: Theme.of(context).colorScheme.onPrimary,
|
||||||
onPressed: () => addMeal(context),
|
onPressed: () => addMeal(context),
|
||||||
|
@ -44,9 +40,8 @@ class SummaryHeader extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class SummaryWidget extends StatelessWidget {
|
class SummaryWidget extends StatelessWidget {
|
||||||
static final MAX_WIDTH = 920.0;
|
static const maxWidth = 920.0;
|
||||||
|
|
||||||
final Diary diary;
|
final Diary diary;
|
||||||
final ApiClient apiClient;
|
final ApiClient apiClient;
|
||||||
|
@ -75,8 +70,8 @@ class SummaryWidget extends StatelessWidget {
|
||||||
var theme = Theme.of(context);
|
var theme = Theme.of(context);
|
||||||
var colorScheme = theme.colorScheme;
|
var colorScheme = theme.colorScheme;
|
||||||
|
|
||||||
var width_avail = MediaQuery.of(context).size.width;
|
var widthAvail = MediaQuery.of(context).size.width;
|
||||||
var width = width_avail > MAX_WIDTH ? MAX_WIDTH : width_avail;
|
var width = widthAvail > maxWidth ? maxWidth : widthAvail;
|
||||||
|
|
||||||
return Center(
|
return Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
@ -100,11 +95,12 @@ class SummaryWidget extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 24),
|
padding:
|
||||||
|
const EdgeInsets.symmetric(vertical: 12, horizontal: 24),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
SummaryHeader(diary: diary, addMeal: _addMeal),
|
SummaryHeader(diary: diary, addMeal: _addMeal),
|
||||||
MacroHeaderWidget(
|
const MacroHeaderWidget(
|
||||||
calories: true,
|
calories: true,
|
||||||
),
|
),
|
||||||
MacroEntryWidget(
|
MacroEntryWidget(
|
||||||
|
|
36
pubspec.lock
36
pubspec.lock
|
@ -65,6 +65,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.6"
|
version: "1.0.6"
|
||||||
|
fading_edge_scrollview:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: fading_edge_scrollview
|
||||||
|
sha256: c25c2231652ce774cc31824d0112f11f653881f43d7f5302c05af11942052031
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -114,10 +122,10 @@ packages:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: flutter_lints
|
name: flutter_lints
|
||||||
sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7
|
sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.1"
|
version: "3.0.2"
|
||||||
flutter_plugin_android_lifecycle:
|
flutter_plugin_android_lifecycle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -256,6 +264,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "3.0.0"
|
||||||
|
marquee:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: marquee
|
||||||
|
sha256: "4b5243d2804373bdc25fc93d42c3b402d6ec1f4ee8d0bb72276edd04ae7addb8"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.3"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -340,10 +356,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler
|
name: permission_handler
|
||||||
sha256: "74e962b7fad7ff75959161bb2c0ad8fe7f2568ee82621c9c2660b751146bfe44"
|
sha256: "18bf33f7fefbd812f37e72091a15575e72d5318854877e0e4035a24ac1113ecb"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "11.3.0"
|
version: "11.3.1"
|
||||||
permission_handler_android:
|
permission_handler_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -356,10 +372,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_apple
|
name: permission_handler_apple
|
||||||
sha256: "92861b0f0c2443dd8898398c2baa4f1ae925109b5909ae4a17d0108a6a788932"
|
sha256: e9ad66020b89ff1b63908f247c2c6f931c6e62699b756ef8b3c4569350cd8662
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.4.2"
|
version: "9.4.4"
|
||||||
permission_handler_html:
|
permission_handler_html:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -372,10 +388,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_platform_interface
|
name: permission_handler_platform_interface
|
||||||
sha256: "23dfba8447c076ab5be3dee9ceb66aad345c4a648f0cac292c77b1eb0e800b78"
|
sha256: "48d4fcf201a1dad93ee869ab0d4101d084f49136ec82a8a06ed9cfeacab9fd20"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.2.0"
|
version: "4.2.1"
|
||||||
permission_handler_windows:
|
permission_handler_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -505,10 +521,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: win32
|
name: win32
|
||||||
sha256: "8cb58b45c47dcb42ab3651533626161d6b67a2921917d8d429791f76972b3480"
|
sha256: "0a989dc7ca2bb51eac91e8fd00851297cfffd641aa7538b165c62637ca0eaa4a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.3.0"
|
version: "5.4.0"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -42,6 +42,7 @@ dependencies:
|
||||||
google_fonts: ^6.2.1
|
google_fonts: ^6.2.1
|
||||||
flex_color_scheme: ^7.3.1
|
flex_color_scheme: ^7.3.1
|
||||||
blur: ^3.1.0
|
blur: ^3.1.0
|
||||||
|
marquee: ^2.2.3
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
Loading…
Reference in a new issue