feat: add statistics component logic with dedicated box and day,week,month filtering
parent
da079c7728
commit
b33cb8a8e3
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:ernaehrung/android/components/food_list_component.dart';
|
import 'package:ernaehrung/android/components/food_list_component.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
import 'meal_page_text/title_component.dart';
|
import 'meal_page_text/title_component.dart';
|
||||||
|
|
||||||
class MealPageStatisticsFoodComponent extends StatelessWidget {
|
class MealPageStatisticsFoodComponent extends StatelessWidget {
|
||||||
|
|
@ -14,12 +14,12 @@ class MealPageStatisticsFoodComponent extends StatelessWidget {
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: const [
|
children: [
|
||||||
SizedBox(
|
const SizedBox(
|
||||||
height: 24,
|
height: 24,
|
||||||
),
|
),
|
||||||
TitleComponent("Nahrung"),
|
const TitleComponent("Nahrung"),
|
||||||
FoodComponent()
|
FoodComponent(box: Hive.box('STATISTICS_REDUCED'),)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
|
|
||||||
import '../models/food.dart';
|
import '../models/food.dart';
|
||||||
import '../pages/nav_pages/search_food.dart';
|
import '../pages/nav_pages/search_food.dart';
|
||||||
|
|
||||||
class CardComponent extends StatefulWidget {
|
class CardComponent extends StatefulWidget {
|
||||||
final String eatingMealName;
|
final String eatingMealName;
|
||||||
final List<Food> selectedMeal;
|
final List<Food> selectedMeal;
|
||||||
|
final bool addButtonVisible;
|
||||||
|
|
||||||
const CardComponent(
|
const CardComponent(
|
||||||
{Key? key, required this.eatingMealName, required this.selectedMeal})
|
{Key? key, required this.eatingMealName, required this.selectedMeal, this.addButtonVisible = true})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -58,19 +58,24 @@ class _CardComponentState extends State<CardComponent> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget getElevatedButton() {
|
Widget getElevatedButton() {
|
||||||
return ElevatedButton(
|
if(widget.addButtonVisible){
|
||||||
onPressed: () async {
|
return ElevatedButton(
|
||||||
Navigator.of(context).push(createRoute(widget.eatingMealName));
|
onPressed: () async {
|
||||||
},
|
Navigator.of(context).push(createRoute(widget.eatingMealName));
|
||||||
style: ElevatedButton.styleFrom(
|
},
|
||||||
shape: const CircleBorder(),
|
style: ElevatedButton.styleFrom(
|
||||||
padding: const EdgeInsets.all(0),
|
shape: const CircleBorder(),
|
||||||
),
|
padding: const EdgeInsets.all(0),
|
||||||
child: const Text(
|
),
|
||||||
'+',
|
child: const Text(
|
||||||
style: TextStyle(fontSize: 28),
|
'+',
|
||||||
),
|
style: TextStyle(fontSize: 28),
|
||||||
);
|
),
|
||||||
|
);
|
||||||
|
}else{
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int getCountedCalories() {
|
int getCountedCalories() {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:percent_indicator/linear_percent_indicator.dart';
|
||||||
|
|
||||||
|
class DietChatComponent extends StatefulWidget {
|
||||||
|
final double fatPercentPerThousandCalorie = 3.7;
|
||||||
|
final double proteinPercentPerThousandCalorie = 4.5;
|
||||||
|
final double carbsPercentPerThousandCalorie = 12.8;
|
||||||
|
|
||||||
|
final String carbs = "Kohlenhydrate";
|
||||||
|
final String protein = "Protein";
|
||||||
|
final String fat = "Fett";
|
||||||
|
|
||||||
|
late String fatGramm, carbGramm, proteinGramm = "";
|
||||||
|
late double fatSummary, carbSummary, proteinSummary = 0.0;
|
||||||
|
|
||||||
|
DietChatComponent(int calorienSummary, {super.key, int calorienLeft = 0}){
|
||||||
|
fatSummary = (calorienSummary / 100) * fatPercentPerThousandCalorie;
|
||||||
|
carbSummary = (calorienSummary / 100) * carbsPercentPerThousandCalorie;
|
||||||
|
proteinSummary = (calorienSummary / 100) * proteinPercentPerThousandCalorie;
|
||||||
|
fatGramm = '0 / $fatSummary g';
|
||||||
|
carbGramm = '0 / $carbSummary g';
|
||||||
|
proteinGramm = '0 / $proteinSummary g';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<DietChatComponent> createState() => _DietChatComponentState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DietChatComponentState extends State<DietChatComponent> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
Text(widget.carbs),
|
||||||
|
LinearPercentIndicator(
|
||||||
|
width: 100.0,
|
||||||
|
lineHeight: 8.0,
|
||||||
|
percent: 0.9,
|
||||||
|
progressColor: Colors.blue,
|
||||||
|
),
|
||||||
|
Text(widget.carbGramm)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
Text(widget.protein),
|
||||||
|
LinearPercentIndicator(
|
||||||
|
width: 100.0,
|
||||||
|
lineHeight: 8.0,
|
||||||
|
percent: 0.9,
|
||||||
|
progressColor: Colors.blue,
|
||||||
|
),
|
||||||
|
Text(widget.proteinGramm)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
Text(widget.fat),
|
||||||
|
LinearPercentIndicator(
|
||||||
|
width: 100.0,
|
||||||
|
lineHeight: 8.0,
|
||||||
|
percent: 0.9,
|
||||||
|
progressColor: Colors.blue,
|
||||||
|
),
|
||||||
|
Text(widget.fatGramm)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,26 +1,17 @@
|
||||||
|
import 'package:ernaehrung/android/config/cast_helper.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:hive/hive.dart';
|
|
||||||
import 'package:hive_flutter/adapters.dart';
|
import 'package:hive_flutter/adapters.dart';
|
||||||
|
|
||||||
import '../models/food.dart';
|
|
||||||
import 'card_component.dart';
|
import 'card_component.dart';
|
||||||
|
|
||||||
class FoodComponent extends StatelessWidget {
|
class FoodComponent extends StatelessWidget {
|
||||||
const FoodComponent({Key? key}) : super(key: key);
|
final Box box;
|
||||||
|
const FoodComponent({super.key, required this.box});
|
||||||
List<Food> castDynamicToListFood(List<dynamic> dynamicList) {
|
|
||||||
List<Food> foodList = [];
|
|
||||||
for (Food element in dynamicList) {
|
|
||||||
foodList.add(element);
|
|
||||||
}
|
|
||||||
|
|
||||||
return foodList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
||||||
return ValueListenableBuilder(
|
return ValueListenableBuilder(
|
||||||
valueListenable: Hive.box("TODAY").listenable(),
|
valueListenable: box.listenable(),
|
||||||
builder: (context, box, widget) {
|
builder: (context, box, widget) {
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
primary: false,
|
primary: false,
|
||||||
|
|
@ -32,10 +23,13 @@ class FoodComponent extends StatelessWidget {
|
||||||
} else {
|
} else {
|
||||||
return CardComponent(
|
return CardComponent(
|
||||||
eatingMealName: box.keyAt(i).toString(),
|
eatingMealName: box.keyAt(i).toString(),
|
||||||
selectedMeal:
|
selectedMeal: castDynamicToListFood(box.getAt(i)),
|
||||||
castDynamicToListFood(box.getAt(i)));
|
addButtonVisible: box.name != 'statistics_reduced',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import 'package:assorted_layout_widgets/assorted_layout_widgets.dart';
|
import 'package:assorted_layout_widgets/assorted_layout_widgets.dart';
|
||||||
|
import 'package:ernaehrung/android/config/cast_helper.dart';
|
||||||
import 'package:ernaehrung/android/config/statistics.dart';
|
import 'package:ernaehrung/android/config/statistics.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import '../config/setup_todaybox_config.dart';
|
|
||||||
import '../models/food.dart';
|
import '../models/food.dart';
|
||||||
|
|
||||||
class SearchedFoodComponent extends StatefulWidget {
|
class SearchedFoodComponent extends StatefulWidget {
|
||||||
|
|
@ -19,35 +19,22 @@ class _SearchFoodComponentState extends State<SearchedFoodComponent> {
|
||||||
StatisticsService statisticsService = StatisticsService();
|
StatisticsService statisticsService = StatisticsService();
|
||||||
|
|
||||||
void storeFood() async {
|
void storeFood() async {
|
||||||
statisticsService.addItemToStatisticsBox(widget.food, widget.cardName);
|
statisticsService.addItemToMainBox(widget.food, widget.cardName);
|
||||||
final todayBox = Hive.box(dotenv.env['TODAY_BOX']!);
|
final todayBox = Hive.box(dotenv.env['TODAY_BOX']!);
|
||||||
if (!todayBox.isOpen){
|
if (!todayBox.isOpen){
|
||||||
Hive.openBox(dotenv.env['TODAY_BOX']!);
|
Hive.openBox(dotenv.env['TODAY_BOX']!);
|
||||||
}
|
}
|
||||||
|
addValuesToList(todayBox, widget.cardName, [widget.food]);
|
||||||
|
}
|
||||||
|
|
||||||
final todayBoxDateField = todayBox.containsKey(dotenv.env['DATE_FIELD']!.toString());
|
void addValuesToList(box, String key, List<Food> newValues){
|
||||||
final todayBoxEatingField = todayBox.containsKey(widget.cardName.toUpperCase().toString());
|
List<Food> existingList = castDynamicToListFood(box.get(key));
|
||||||
|
for(int i = 0; i < newValues.length;i++){
|
||||||
if (todayBoxDateField && todayBoxEatingField){
|
if(!existingList.contains(newValues[i])){
|
||||||
updateFoodInStorage(todayBox);
|
existingList.add(newValues[i]);
|
||||||
}else{
|
}
|
||||||
addFoodToStorage(todayBox);
|
|
||||||
}
|
}
|
||||||
}
|
box.put(key, existingList);
|
||||||
|
|
||||||
void updateFoodInStorage(dynamic todayBox) async {
|
|
||||||
final values = todayBox.get(widget.cardName.toUpperCase());
|
|
||||||
values.add(widget.food);
|
|
||||||
|
|
||||||
await todayBox.put(widget.cardName.toUpperCase(), values);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addFoodToStorage(dynamic todayBox) async{
|
|
||||||
List<Food> foods = [];
|
|
||||||
foods.add(widget.food);
|
|
||||||
todayBox.put(widget.cardName.toUpperCase(), foods);
|
|
||||||
|
|
||||||
todayBox.put(dotenv.env['DATE_FIELD']!, getFormatedTodayDate());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,37 @@
|
||||||
import 'package:ernaehrung/android/components/meal_page_text/days_text_component.dart';
|
import 'package:ernaehrung/android/components/meal_page_text/days_text_component.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:ernaehrung/android/config/statistics.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class DaysMealPageComponent extends StatelessWidget {
|
enum TimeSpan {
|
||||||
final String dayText = "Tag";
|
day,
|
||||||
final String weekText = "Woche";
|
week,
|
||||||
final String monthText = "Monat";
|
month
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class DaysMealPageComponent extends StatefulWidget {
|
||||||
const DaysMealPageComponent({Key? key}) : super(key: key);
|
const DaysMealPageComponent({Key? key}) : super(key: key);
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() => _DaysMealPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class _DaysMealPageState extends State<DaysMealPageComponent> {
|
||||||
|
int activatedIndex = 0;
|
||||||
|
StatisticsService statisticsService = StatisticsService();
|
||||||
|
|
||||||
|
void updateValue(int index) {
|
||||||
|
setState(() {
|
||||||
|
activatedIndex = index;
|
||||||
|
if(activatedIndex == 0){
|
||||||
|
statisticsService.updateReducedBoxByTimespan(TimeSpan.day);
|
||||||
|
}else if(activatedIndex == 1){
|
||||||
|
statisticsService.updateReducedBoxByTimespan(TimeSpan.week);
|
||||||
|
}else if(activatedIndex == 2){
|
||||||
|
statisticsService.updateReducedBoxByTimespan(TimeSpan.month);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
@ -15,11 +40,34 @@ class DaysMealPageComponent extends StatelessWidget {
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
DaysTextComponent(dayText),
|
DaysTextComponent(
|
||||||
DaysTextComponent(weekText),
|
timeSpan: TimeSpan.day,
|
||||||
DaysTextComponent(monthText),
|
textColor: activatedIndex == 0
|
||||||
|
? const Color(0xff47a44b)
|
||||||
|
: const Color(0xff000000),
|
||||||
|
onPressed: updateValue,
|
||||||
|
index: 0
|
||||||
|
|
||||||
|
),
|
||||||
|
DaysTextComponent(
|
||||||
|
timeSpan: TimeSpan.week,
|
||||||
|
textColor: activatedIndex == 1
|
||||||
|
? const Color(0xff47a44b)
|
||||||
|
: const Color(0xff000000),
|
||||||
|
onPressed: updateValue,
|
||||||
|
index: 1
|
||||||
|
),
|
||||||
|
DaysTextComponent(
|
||||||
|
timeSpan: TimeSpan.month,
|
||||||
|
textColor: activatedIndex == 2
|
||||||
|
? const Color(0xff47a44b)
|
||||||
|
: const Color(0xff000000),
|
||||||
|
onPressed: updateValue,
|
||||||
|
index: 2
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,40 @@
|
||||||
|
import 'package:ernaehrung/android/components/meal_page_text/days_component.dart';
|
||||||
|
import 'package:ernaehrung/android/config/statistics.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class DaysTextComponent extends StatelessWidget {
|
class DaysTextComponent extends StatelessWidget {
|
||||||
final String name;
|
late final String timeSpan;
|
||||||
|
late final TimeSpan timespan;
|
||||||
|
Function(int i) onPressed;
|
||||||
|
int index;
|
||||||
|
Color textColor;
|
||||||
|
late StatisticsService statisticsService;
|
||||||
|
|
||||||
const DaysTextComponent(this.name, {super.key});
|
DaysTextComponent({super.key, required TimeSpan timeSpan, required this.textColor, required this.onPressed, required this.index}){
|
||||||
|
timespan = timeSpan;
|
||||||
|
switch(timeSpan){
|
||||||
|
case TimeSpan.day:
|
||||||
|
this.timeSpan = 'Tag';
|
||||||
|
break;
|
||||||
|
case TimeSpan.week:
|
||||||
|
this.timeSpan = 'Woche';
|
||||||
|
break;
|
||||||
|
case TimeSpan.month:
|
||||||
|
this.timeSpan = 'Monat';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return TextButton(
|
return TextButton(
|
||||||
onPressed: () {},
|
onPressed: () {
|
||||||
|
onPressed(index);
|
||||||
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
name,
|
timeSpan,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
color: Color.fromARGB(255, 211, 211, 211),
|
color: textColor,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
import '../models/food.dart';
|
||||||
|
|
||||||
|
List<Food> castDynamicToListFood(List<dynamic> dynamicList) {
|
||||||
|
List<Food> foodList = [];
|
||||||
|
for (Food element in dynamicList) {
|
||||||
|
foodList.add(element);
|
||||||
|
}
|
||||||
|
return foodList;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String,List<Food>> castDynamicMap(Map<dynamic,dynamic> dynamicMap){
|
||||||
|
Map<String,List<Food>> foodMap = {};
|
||||||
|
for(dynamic key in dynamicMap.keys){
|
||||||
|
foodMap.putIfAbsent(key as String , () => castDynamicToListFood(dynamicMap[key]));
|
||||||
|
}
|
||||||
|
return foodMap;
|
||||||
|
}
|
||||||
|
|
@ -4,51 +4,22 @@ import '../models/food.dart';
|
||||||
|
|
||||||
final List<Food> emptyList = [];
|
final List<Food> emptyList = [];
|
||||||
|
|
||||||
Future<void> setupTodayBox() async {
|
|
||||||
final todayBoxExist = await Hive.boxExists(dotenv.env['TODAY_BOX']!);
|
|
||||||
final todayBoxOpened = Hive.isBoxOpen(dotenv.env['TODAY_BOX']!);
|
|
||||||
|
|
||||||
if (!todayBoxOpened && !todayBoxExist){
|
|
||||||
Hive.openBox(dotenv.env['TODAY_BOX']!);
|
|
||||||
}
|
|
||||||
|
|
||||||
setupEatingKeys();
|
void setupTodayBox() async{
|
||||||
}
|
|
||||||
|
|
||||||
void setupEatingKeys() async {
|
|
||||||
final todayBox = Hive.box(dotenv.env['TODAY_BOX']!);
|
final todayBox = Hive.box(dotenv.env['TODAY_BOX']!);
|
||||||
final breakfastExist = todayBox.containsKey(dotenv.env['BREAKFAST_FIELD']!);
|
putIfKeyNotExists(todayBox, 'FRÜHSTÜCK', []);
|
||||||
final lunchExist = todayBox.containsKey(dotenv.env['LUNCH_FIELD']!);
|
putIfKeyNotExists(todayBox, 'MITTAGESSEN', []);
|
||||||
final dinnerExist = todayBox.containsKey(dotenv.env['DINNER_FIELD']!);
|
putIfKeyNotExists(todayBox, 'ABENDESSEN', []);
|
||||||
|
|
||||||
if (!breakfastExist){
|
|
||||||
todayBox.put(dotenv.env['BREAKFAST_FIELD']!, emptyList);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lunchExist){
|
|
||||||
todayBox.put(dotenv.env['LUNCH_FIELD']!, emptyList);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dinnerExist){
|
|
||||||
todayBox.put(dotenv.env['DINNER_FIELD']!, emptyList);
|
|
||||||
}
|
|
||||||
|
|
||||||
setupDateField();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupDateField() async{
|
|
||||||
final todayBox = Hive.box(dotenv.env['TODAY_BOX']!);
|
|
||||||
final dateExist = todayBox.containsKey(dotenv.env['DATE_FIELD']!);
|
|
||||||
|
|
||||||
if (!dateExist){
|
|
||||||
todayBox.put(dotenv.env['DATE_FIELD']!, getFormatedTodayDate());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void moveTodayBoxDataToYesterdayAndBefore() async{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void putIfKeyNotExists(Box box, String key, List<Food> value) {
|
||||||
|
if (!box.containsKey(key)) {
|
||||||
|
box.put(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
String getFormatedTodayDate(){
|
String getFormatedTodayDate(){
|
||||||
return DateTime.now().toString().substring(0,10);
|
return DateTime.now().toString().substring(0,10);
|
||||||
}
|
}
|
||||||
|
|
@ -1,49 +1,185 @@
|
||||||
import 'package:hive/hive.dart';
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:ernaehrung/android/components/meal_page_text/days_component.dart';
|
||||||
|
import 'package:ernaehrung/android/config/cast_helper.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
import '../models/food.dart';
|
import '../models/food.dart';
|
||||||
|
|
||||||
class StatisticsService {
|
class StatisticsService {
|
||||||
|
final String reducedStatisticsBoxName = 'STATISTICS_REDUCED';
|
||||||
final String boxName = 'STATISTICS';
|
final String mainStatisticsBoxName = 'STATISTICS_MAIN';
|
||||||
|
|
||||||
StatisticsService() {
|
StatisticsService() {
|
||||||
initBox();
|
initBoxes();
|
||||||
}
|
}
|
||||||
|
|
||||||
initBox()async{
|
initBoxes()async{
|
||||||
await Hive.openBox(boxName);
|
Box reducedBox = Hive.box(reducedStatisticsBoxName);
|
||||||
|
putIfKeyNotExists(reducedBox, 'FRÜHSTÜCK', []);
|
||||||
|
putIfKeyNotExists(reducedBox, 'MITTAGESSEN', []);
|
||||||
|
putIfKeyNotExists(reducedBox, 'ABENDESSEN', []);
|
||||||
|
updateReducedBoxByTimespan(TimeSpan.day);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void putIfKeyNotExists(Box box, String key, dynamic value) {
|
||||||
|
if (!box.containsKey(key)) {
|
||||||
|
box.put(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
addItemToStatisticsBox(Food value, String mealType){
|
updateReducedBoxByTimespan(TimeSpan timeSpan){
|
||||||
|
clearReducedBoxBeforeUpdate();
|
||||||
|
print(timeSpan);
|
||||||
|
DateTime now = DateTime.now();
|
||||||
|
int timestamp = now.millisecondsSinceEpoch.toInt() ~/ 1000;
|
||||||
|
switch(timeSpan){
|
||||||
|
case TimeSpan.day:
|
||||||
|
getNewFoodAndUpdateReducedBoxByTimestamp(timestamp);
|
||||||
|
break;
|
||||||
|
case TimeSpan.week:
|
||||||
|
List<int> currentWeek = getTimestampsByTimestampAndTimespan(TimeSpan.week,timestamp);
|
||||||
|
for(int i = 0;i < currentWeek.length;i++){
|
||||||
|
getNewFoodAndUpdateReducedBoxByTimestamp(currentWeek[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TimeSpan.month:
|
||||||
|
List<int> currentWeek = getTimestampsByTimestampAndTimespan(TimeSpan.month,timestamp);
|
||||||
|
for(int i = 0;i < currentWeek.length;i++){
|
||||||
|
getNewFoodAndUpdateReducedBoxByTimestamp(currentWeek[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void getNewFoodAndUpdateReducedBoxByTimestamp(int timestamp){
|
||||||
|
Map<String,List<Food>> newFood = getFoodMapForGivenTimestampFromMainBox(timestamp);
|
||||||
|
if(newFood.keys.isNotEmpty){
|
||||||
|
setElementsOfReducedBox(newFood);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<int> getTimestampsByTimestampAndTimespan(TimeSpan timespan, int timestamp) {
|
||||||
|
int range = timespan == TimeSpan.week ? 7 : 31;
|
||||||
|
int targetWeekday = DateTime.monday; // Example target weekday (Monday)
|
||||||
|
DateTime currentDateTime = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
|
||||||
|
int currentWeekday = currentDateTime.weekday;
|
||||||
|
int daysToAdd = targetWeekday - currentWeekday;
|
||||||
|
DateTime targetDateTime = currentDateTime.add(Duration(days: daysToAdd));
|
||||||
|
|
||||||
|
List<int> timestampsForWeekdays = [];
|
||||||
|
for (int i = 0; i < range; i++) {
|
||||||
|
timestampsForWeekdays.add(targetDateTime.millisecondsSinceEpoch ~/ 1000);
|
||||||
|
targetDateTime = targetDateTime.add(const Duration(days: 1));
|
||||||
|
}
|
||||||
|
return timestampsForWeekdays;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearReducedBoxBeforeUpdate(){
|
||||||
|
Box box = Hive.box(reducedStatisticsBoxName);
|
||||||
|
for(int i = 0; i < box.keys.length;i++){
|
||||||
|
box.put(box.keys.elementAt(i), []);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setElementsOfReducedBox(Map<String,List<Food>> newFood){
|
||||||
|
Box box = Hive.box(reducedStatisticsBoxName);
|
||||||
|
Iterable<String> keys = newFood.keys;
|
||||||
|
for(int i = 0; i < keys.length;i++){
|
||||||
|
addValuesToList(box, keys.elementAt(i), newFood[keys.elementAt(i)] ?? []);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addValuesToList(Box box, String key, List<Food> newValues){
|
||||||
|
List<Food> existingList = castDynamicToListFood(box.get(key));
|
||||||
|
for(int i = 0; i < newValues.length;i++){
|
||||||
|
if(!existingList.contains(newValues[i])){
|
||||||
|
existingList.add(newValues[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
box.put(key, existingList);
|
||||||
|
}
|
||||||
|
|
||||||
|
getDayAsIntFromTimestamp(int timestamp){
|
||||||
|
DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
|
||||||
|
return dateTime.day;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String,List<Food>> getFoodMapForGivenTimestampFromMainBox(int timestamp){
|
||||||
|
Box box = Hive.box(mainStatisticsBoxName);
|
||||||
|
dynamic matchingTimestamp = getMatchingTimeStamp(box, timestamp);
|
||||||
|
if(matchingTimestamp != null){
|
||||||
|
return castDynamicMap(box.get(matchingTimestamp));
|
||||||
|
}
|
||||||
|
return <String,List<Food>>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
getMatchingTimeStamp(Box box,int newTimestamp){
|
||||||
|
if(box.keys.isNotEmpty){
|
||||||
|
for(int i = 0; i < box.keys.length;i++){
|
||||||
|
int timestamp = box.keys.elementAt(i);
|
||||||
|
if(isDateEqual(newTimestamp, timestamp)){
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getMonthAsIntFromTimestamp(int timestamp){
|
||||||
|
DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
|
||||||
|
return dateTime.month;
|
||||||
|
}
|
||||||
|
|
||||||
|
getYearAsIntFromTimestamp(int timestamp){
|
||||||
|
DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
|
||||||
|
return dateTime.year;
|
||||||
|
}
|
||||||
|
|
||||||
|
isDateEqual(int timestamp1, int timestamp2){
|
||||||
|
return
|
||||||
|
getDayAsIntFromTimestamp(timestamp1) == getDayAsIntFromTimestamp(timestamp2) &&
|
||||||
|
getMonthAsIntFromTimestamp(timestamp1) == getMonthAsIntFromTimestamp(timestamp2) &&
|
||||||
|
getYearAsIntFromTimestamp(timestamp1) == getYearAsIntFromTimestamp(timestamp2);
|
||||||
|
}
|
||||||
|
|
||||||
|
addItemToMainBox(Food value, String mealType){
|
||||||
// Hive.deleteFromDisk();
|
// Hive.deleteFromDisk();
|
||||||
Box box = Hive.box(boxName);
|
Box box = Hive.box(mainStatisticsBoxName);
|
||||||
DateTime dateTime = DateTime.now();
|
DateTime dateTime = DateTime.now();
|
||||||
int timestamp = dateTime.millisecondsSinceEpoch.toInt() ~/ 1000;
|
|
||||||
print(timestamp);
|
// DEBUG
|
||||||
Map<String, List<Food>>? valueMap = box.get(timestamp);
|
//DateTime dateTime = getRandomTimestampForTesting();
|
||||||
valueMap ??= {
|
|
||||||
"FRÜHSTÜCK": [],
|
int newTimestamp = dateTime.millisecondsSinceEpoch.toInt() ~/ 1000;
|
||||||
"MITTAGESSEN": [],
|
|
||||||
"ABENDESSEN": []
|
dynamic matchingTimestamp = getMatchingTimeStamp(box, newTimestamp);
|
||||||
};
|
if(matchingTimestamp != null){
|
||||||
|
newTimestamp = matchingTimestamp;
|
||||||
|
}
|
||||||
|
Map<String, List<Food>>? valueMap = castDynamicMap(box.get(newTimestamp));
|
||||||
List<Food> values = [];
|
List<Food> values = [];
|
||||||
if(valueMap.containsKey(mealType)){
|
if(valueMap.containsKey(mealType)){
|
||||||
values = valueMap[mealType]!;
|
values = valueMap[mealType]!;
|
||||||
}
|
}
|
||||||
values.add(value);
|
values.add(value);
|
||||||
valueMap[mealType] = values;
|
valueMap[mealType] = values;
|
||||||
box.put(timestamp, valueMap);
|
box.put(newTimestamp, valueMap);
|
||||||
showItems();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
num getAllCaloriesByTimestamp(DateTime date){
|
getRandomTimestampForTesting(){
|
||||||
Box box = Hive.box(boxName);
|
DateTime now = DateTime.now();
|
||||||
|
DateTime startOfWeek = now.subtract(Duration(days: now.weekday - 1));
|
||||||
|
DateTime endOfWeek = startOfWeek.add(Duration(days: 6));
|
||||||
|
|
||||||
|
Random random = Random();
|
||||||
|
int randomMilliseconds = random.nextInt(endOfWeek.millisecondsSinceEpoch - startOfWeek.millisecondsSinceEpoch);
|
||||||
|
DateTime randomTimestamp = startOfWeek.add(Duration(milliseconds: randomMilliseconds));
|
||||||
|
|
||||||
|
return randomTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
num getAllCaloriesByBoxAndTimestamp(Box box,DateTime date){
|
||||||
int timestamp = date.millisecondsSinceEpoch.toInt() ~/ 1000;
|
int timestamp = date.millisecondsSinceEpoch.toInt() ~/ 1000;
|
||||||
Map<String, List<Food>>? valueMap = box.get(timestamp);
|
Map<String, List<Food>>? valueMap = castDynamicMap(box.get(timestamp));
|
||||||
if(valueMap == null){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
num sum = 0;
|
num sum = 0;
|
||||||
for(var mealType in valueMap.keys){
|
for(var mealType in valueMap.keys){
|
||||||
if(valueMap.containsKey(mealType)){
|
if(valueMap.containsKey(mealType)){
|
||||||
|
|
@ -56,13 +192,9 @@ class StatisticsService {
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
num getCaloriesByTimestampAndMealType(DateTime date, String mealType){
|
num getCaloriesByTimestampAndMealTypeAndBox(Box box,DateTime date, String mealType){
|
||||||
Box box = Hive.box(boxName);
|
|
||||||
int timestamp = date.millisecondsSinceEpoch.toInt() ~/ 1000;
|
int timestamp = date.millisecondsSinceEpoch.toInt() ~/ 1000;
|
||||||
Map<String, List<Food>>? valueMap = box.get(timestamp);
|
Map<String, List<Food>>? valueMap = castDynamicMap(box.get(timestamp));
|
||||||
if(valueMap == null){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
num sum = 0;
|
num sum = 0;
|
||||||
if(valueMap.containsKey(mealType)){
|
if(valueMap.containsKey(mealType)){
|
||||||
List<Food> values = valueMap[mealType]!;
|
List<Food> values = valueMap[mealType]!;
|
||||||
|
|
@ -74,8 +206,14 @@ class StatisticsService {
|
||||||
}
|
}
|
||||||
|
|
||||||
showItems(){
|
showItems(){
|
||||||
print("ITEMS");
|
print("Statistics.dart - showItems() - ITEMS");
|
||||||
print(Hive.box(boxName).keys);
|
//Hive.box(boxName).clear();
|
||||||
|
print(Hive.box(mainStatisticsBoxName).keys.length);
|
||||||
|
for(int i = 0; i < Hive.box(mainStatisticsBoxName).keys.length; i++){
|
||||||
|
print(Hive.box(mainStatisticsBoxName).keys.elementAt(i));
|
||||||
|
print(Hive.box(mainStatisticsBoxName).values.elementAt(i));
|
||||||
|
//print(Hive.box(boxName).keys.elementAt(i) + " " + Hive.box(boxName).values.elementAt(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
part 'food.g.dart';
|
part 'food.g.dart';
|
||||||
|
|
||||||
@HiveType(typeId: 1)
|
@HiveType(typeId: 0)
|
||||||
class Food {
|
class Food {
|
||||||
Food(this.id, this.name, this.foodGroup, this.calories, this.fatg,
|
Food(this.id, this.name, this.foodGroup, this.calories, this.fatg,
|
||||||
this.proteing, this.carbohydrateg, this.sugarsg, this.fiberg);
|
this.proteing, this.carbohydrateg, this.sugarsg, this.fiberg);
|
||||||
|
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'food.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// TypeAdapterGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
class FoodAdapter extends TypeAdapter<Food> {
|
|
||||||
@override
|
|
||||||
final int typeId = 1;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Food read(BinaryReader reader) {
|
|
||||||
final numOfFields = reader.readByte();
|
|
||||||
final fields = <int, dynamic>{
|
|
||||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
|
||||||
};
|
|
||||||
return Food(
|
|
||||||
fields[0] as dynamic,
|
|
||||||
fields[1] as dynamic,
|
|
||||||
fields[2] as dynamic,
|
|
||||||
fields[3] as dynamic,
|
|
||||||
fields[4] as dynamic,
|
|
||||||
fields[5] as dynamic,
|
|
||||||
fields[6] as dynamic,
|
|
||||||
fields[7] as dynamic,
|
|
||||||
fields[8] as dynamic,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void write(BinaryWriter writer, Food obj) {
|
|
||||||
writer
|
|
||||||
..writeByte(9)
|
|
||||||
..writeByte(0)
|
|
||||||
..write(obj.id)
|
|
||||||
..writeByte(1)
|
|
||||||
..write(obj.name)
|
|
||||||
..writeByte(2)
|
|
||||||
..write(obj.foodGroup)
|
|
||||||
..writeByte(3)
|
|
||||||
..write(obj.calories)
|
|
||||||
..writeByte(4)
|
|
||||||
..write(obj.fatg)
|
|
||||||
..writeByte(5)
|
|
||||||
..write(obj.proteing)
|
|
||||||
..writeByte(6)
|
|
||||||
..write(obj.carbohydrateg)
|
|
||||||
..writeByte(7)
|
|
||||||
..write(obj.sugarsg)
|
|
||||||
..writeByte(8)
|
|
||||||
..write(obj.fiberg);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => typeId.hashCode;
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) =>
|
|
||||||
identical(this, other) ||
|
|
||||||
other is FoodAdapter &&
|
|
||||||
runtimeType == other.runtimeType &&
|
|
||||||
typeId == other.typeId;
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +1,19 @@
|
||||||
import 'package:ernaehrung/android/components/food_list_component.dart';
|
import 'package:ernaehrung/android/components/food_list_component.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
import '../../components/diet_chart_component.dart';
|
import '../../components/diet_chart_component.dart';
|
||||||
import '../../components/statistics_circular_indicator_component.dart';
|
import '../../components/statistics_circular_indicator_component.dart';
|
||||||
|
|
||||||
class TodayPage extends StatefulWidget {
|
class TodayPage extends StatefulWidget {
|
||||||
final String title;
|
final String title;
|
||||||
final Color backgroundColor = const Color(0xff47a44b);
|
final Color backgroundColor = const Color(0xff47a44b);
|
||||||
|
|
||||||
const TodayPage({Key? key, required this.title}) : super(key: key);
|
const TodayPage({Key? key, required this.title}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<TodayPage> createState() => _TodayPageState();
|
State<TodayPage> createState() => _TodayPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _TodayPageState extends State<TodayPage> {
|
class _TodayPageState extends State<TodayPage> {
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
|
@ -36,7 +34,7 @@ class _TodayPageState extends State<TodayPage> {
|
||||||
children: [
|
children: [
|
||||||
StatisticsPercentComponent(300, 100, 400),
|
StatisticsPercentComponent(300, 100, 400),
|
||||||
DietChatComponent(1500),
|
DietChatComponent(1500),
|
||||||
const FoodComponent(),
|
FoodComponent(box: Hive.box('TODAY'),),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,27 @@
|
||||||
|
import 'package:ernaehrung/android/models/food.dart';
|
||||||
import 'package:ernaehrung/web/web_app.dart';
|
import 'package:ernaehrung/web/web_app.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hive_flutter/hive_flutter.dart';
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||||
import 'android/andoird_app.dart';
|
import 'android/andoird_app.dart';
|
||||||
import 'android/config/setup_todaybox_config.dart';
|
|
||||||
import 'android/models/food.dart';
|
|
||||||
import 'package:flutter/foundation.dart' show defaultTargetPlatform, kIsWeb;
|
import 'package:flutter/foundation.dart' show defaultTargetPlatform, kIsWeb;
|
||||||
|
|
||||||
|
import 'android/config/setup_todaybox_config.dart';
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
await dotenv.load(fileName: ".env");
|
await dotenv.load(fileName: ".env");
|
||||||
await Hive.initFlutter();
|
await Hive.initFlutter();
|
||||||
|
|
||||||
if (!Hive.isAdapterRegistered(1)) {
|
if(!Hive.isAdapterRegistered(0)){
|
||||||
Hive.registerAdapter(FoodAdapter());
|
Hive.registerAdapter(FoodAdapter());
|
||||||
}
|
}
|
||||||
|
//await Hive.deleteFromDisk();
|
||||||
|
|
||||||
|
await Hive.openBox('STATISTICS_REDUCED');
|
||||||
await Hive.openBox(dotenv.env['TODAY_BOX']!);
|
await Hive.openBox('STATISTICS_MAIN');
|
||||||
await setupTodayBox();
|
await Hive.openBox('TODAY');
|
||||||
|
setupTodayBox();
|
||||||
|
//Hive.deleteFromDisk();
|
||||||
|
|
||||||
if(defaultTargetPlatform == TargetPlatform.android){
|
if(defaultTargetPlatform == TargetPlatform.android){
|
||||||
runApp(const AndroidApp());
|
runApp(const AndroidApp());
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,13 @@
|
||||||
import 'package:ernaehrung/android/components/statistics_circular_indicator_component.dart';
|
import 'package:ernaehrung/android/components/statistics_circular_indicator_component.dart';
|
||||||
|
import 'package:ernaehrung/android/config/cast_helper.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:hive_flutter/adapters.dart';
|
import 'package:hive_flutter/adapters.dart';
|
||||||
|
|
||||||
import '../../android/components/card_component.dart';
|
import '../../android/components/card_component.dart';
|
||||||
import '../../android/components/diet_chart_component.dart';
|
import '../../android/components/diet_chart_component.dart';
|
||||||
import '../../android/models/food.dart';
|
|
||||||
|
|
||||||
class SectionComponent extends StatelessWidget {
|
class SectionComponent extends StatelessWidget {
|
||||||
const SectionComponent({Key? key}) : super(key: key);
|
const SectionComponent({Key? key}) : super(key: key);
|
||||||
|
|
||||||
List<Food> castDynamicToListFood(List<dynamic> dynamicList) {
|
|
||||||
List<Food> foodList = [];
|
|
||||||
for (Food element in dynamicList) {
|
|
||||||
foodList.add(element);
|
|
||||||
}
|
|
||||||
|
|
||||||
return foodList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
|
|
@ -38,8 +28,8 @@ class SectionComponent extends StatelessWidget {
|
||||||
}else{
|
}else{
|
||||||
return CardComponent(
|
return CardComponent(
|
||||||
eatingMealName: box.keyAt(i).toString(),
|
eatingMealName: box.keyAt(i).toString(),
|
||||||
selectedMeal: castDynamicToListFood(
|
selectedMeal: castDynamicToListFood(box.getAt(i)),
|
||||||
box.getAt(i)));
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ dev_dependencies:
|
||||||
hive_generator: ^2.0.0
|
hive_generator: ^2.0.0
|
||||||
build_runner: ^2.3.3
|
build_runner: ^2.3.3
|
||||||
|
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
# For information on the generic Dart part of this file, see the
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue