calorimeter/lib/perdate/perdate_widget.dart

158 lines
6.3 KiB
Dart

import 'package:barcode_scan2/barcode_scan2.dart';
import 'package:calorimeter/food_scan/food_fact_lookup.dart';
import 'package:calorimeter/utils/enter_food_controller.dart';
import 'package:calorimeter/utils/scan_food_floating_button.dart';
import 'package:calorimeter/utils/app_drawer.dart';
import 'package:calorimeter/food_entry/food_entry_bloc.dart';
import 'package:calorimeter/perdate/entry_list.dart';
import 'package:calorimeter/storage/storage.dart';
import 'package:calorimeter/utils/calendar_floating_button.dart';
import 'package:calorimeter/utils/rectangular_notch_shape.dart';
import 'package:calorimeter/utils/sum_widget.dart';
import 'package:calorimeter/utils/theme_switcher_button.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
class PerDateWidget extends StatefulWidget {
final DateTime date;
const PerDateWidget({super.key, required this.date});
@override
State<PerDateWidget> createState() => _PerDateWidgetState();
}
class _PerDateWidgetState extends State<PerDateWidget> {
late FoodStorage storage;
late Future<List<FoodEntry>> entriesFuture;
List<FoodEntry> entries = [];
@override
void initState() {
storage = FoodStorage.getInstance();
entriesFuture = storage.getEntriesForDate(widget.date);
entriesFuture.then((val) {
entries = val;
});
super.initState();
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: entriesFuture,
builder: (context, snapshot) {
return snapshot.connectionState != ConnectionState.done
? const Center(child: CircularProgressIndicator())
: MultiProvider(
providers: [
ChangeNotifierProvider(
create: (context) => EnterFoodController()),
BlocProvider(
create: (context) => FoodEntryBloc(
initialState: FoodEntryState(foodEntries: entries),
storage: storage,
forDate: widget.date,
),
)
],
child: BlocBuilder<FoodEntryBloc, FoodEntryState>(
builder: (context, state) {
return Scaffold(
appBar: AppBar(
title:
Text(DateFormat.yMMMMd('de').format(widget.date)),
actions: const [ThemeSwitcherButton()],
),
body: FoodEntryList(entries: state.foodEntries),
bottomNavigationBar: BottomAppBar(
shape: const RectangularNotchShape(),
color: Theme.of(context).colorScheme.secondary,
child: SumWidget(foodEntries: state.foodEntries)),
drawer: const AppDrawer(),
floatingActionButton: OverflowBar(children: [
ScanFoodFloatingButton(
onPressed: () async {
var client = FoodFactLookupClient();
var scanResult = await BarcodeScanner.scan();
if (scanResult.type == ResultType.Cancelled) {
return;
}
if (!context.mounted) return;
if (scanResult.type == ResultType.Error) {
showNewSnackbarWith(context,
"Fehler beim Scannen des Barcodes.");
}
var response = await client
.retrieveFoodInfo(scanResult.rawContent);
if (!context.mounted) return;
if (response.status ==
FoodFactResponseStatus.barcodeNotFound) {
showNewSnackbarWith(context,
"Barcode konnte nicht gefunden werden.");
return;
}
if (response.status ==
FoodFactResponseStatus
.foodFactServerNotReachable) {
showNewSnackbarWith(context,
"OpenFoodFacts-Server konnte nicht erreicht werden.");
return;
}
context.read<EnterFoodController>().set(
response.food!.name,
response.food!.kcalPer100g.toString(),
);
},
),
const SizedBox(width: 8),
CalendarFloatingButton(
startFromDate: widget.date,
onDateSelected: (dateSelected) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return PerDateWidget(date: dateSelected);
},
),
);
},
),
]),
floatingActionButtonLocation:
FloatingActionButtonLocation.endDocked);
}),
);
});
}
void showNewSnackbarWith(BuildContext context, String text) {
var snackbar =
ErrorSnackbar(colorScheme: Theme.of(context).colorScheme, text: text);
ScaffoldMessenger.of(context).clearSnackBars();
ScaffoldMessenger.of(context).showSnackBar(snackbar);
}
}
class ErrorSnackbar extends SnackBar {
final String text;
final ColorScheme colorScheme;
ErrorSnackbar({
required this.text,
required this.colorScheme,
super.key,
}) : super(
content: Text(text, style: TextStyle(color: colorScheme.onError)),
backgroundColor: colorScheme.error);
}