feat: add weeekly ranking list and average calories

feature/chart-progress-page
98spag 2023-05-30 22:09:16 +02:00
parent cc1ea62d2d
commit fcc607043e
6 changed files with 139 additions and 138 deletions

View File

@ -34,7 +34,6 @@ class StatisticsPercentage extends StatelessWidget {
child: ValueListenableBuilder<List<double>>(
valueListenable: StatisticsService.instance.ingredients,
builder: (context, value, child) {
print(value);
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [

View File

@ -6,6 +6,11 @@ String getFoodListStringByFood(String foodName, int count, int calories){
return limitedText;
}
String getWeeklyRankingString(String foodName){
int maxWidth = 50;
String limitedText = foodName.length > maxWidth ? "${foodName.substring(0, maxWidth - 3)} ... " : foodName;
return limitedText;
}
Map<String,List<int>> getMapOfDistinctElementsWithCounterAndCalories(List<Food> foods){
Map<String,List<int>> resultMap = <String,List<int>>{};
@ -18,3 +23,13 @@ Map<String,List<int>> getMapOfDistinctElementsWithCounterAndCalories(List<Food>
}
return resultMap;
}
List<Food> getListOfDistinctElements(List<Food> foods){
List<Food> result = [];
for(int i = 0; i < foods.length;i++){
if(!result.any((element) => element.id == foods[i].id)){
result.add(foods[i]);
}
}
return result;
}

View File

@ -4,6 +4,7 @@ import 'package:ernaehrung/android/config/cast_helper.dart';
import 'package:flutter/cupertino.dart';
import 'package:hive/hive.dart';
import '../models/food.dart';
import 'format_helper.dart';
class StatisticsService {
@ -18,60 +19,66 @@ class StatisticsService {
final String reducedStatisticsBoxName = 'STATISTICS_REDUCED';
final String mainStatisticsBoxName = 'STATISTICS_MAIN';
final String progressStatisticsBoxName = 'STATISTICS_PROGRESS';
ValueNotifier<int> eatenCalories = ValueNotifier<int>(0);
ValueNotifier<List<double>> ingredients = ValueNotifier<List<double>>([0,0,0]);
ValueNotifier<int> dailyAverageForCurrentWeek = ValueNotifier<int>(0);
ValueNotifier<List<Food>> weeklyCaloryRanking = ValueNotifier<List<Food>>([]);
initBoxes()async{
Box reducedBox = Hive.box(reducedStatisticsBoxName);
putIfKeyNotExists(reducedBox, 'FRÜHSTÜCK', []);
putIfKeyNotExists(reducedBox, 'MITTAGESSEN', []);
putIfKeyNotExists(reducedBox, 'ABENDESSEN', []);
Box progressBox = Hive.box(progressStatisticsBoxName);
putIfKeyNotExists([reducedBox,progressBox], 'FRÜHSTÜCK', []);
putIfKeyNotExists([reducedBox,progressBox], 'MITTAGESSEN', []);
putIfKeyNotExists([reducedBox,progressBox], 'ABENDESSEN', []);
updateReducedBoxByTimespan(TimeSpan.day);
}
void putIfKeyNotExists(Box box, String key, dynamic value) {
if (!box.containsKey(key)) {
box.put(key, value);
void putIfKeyNotExists(List<Box> boxes, String key, dynamic value) {
for(int i = 0; i < boxes.length;i++){
if (!boxes[i].containsKey(key)) {
boxes[i].put(key, value);
}
}
}
updateReducedBoxByTimespan(TimeSpan timeSpan){
clearReducedBoxBeforeUpdate();
DateTime now = DateTime.now();
int timestamp = now.millisecondsSinceEpoch.toInt() ~/ 1000;
int timestamp = getTimestampFromNow();
switch(timeSpan){
case TimeSpan.day:
getNewFoodAndUpdateReducedBoxByTimestamp(timestamp);
getNewFoodAndUpdateBoxByTimestampAndBox(timestamp, Hive.box(reducedStatisticsBoxName));
break;
case TimeSpan.week:
List<int> currentWeek = getTimestampsByTimestampAndTimespan(TimeSpan.week,timestamp);
for(int i = 0;i < currentWeek.length;i++){
getNewFoodAndUpdateReducedBoxByTimestamp(currentWeek[i]);
getNewFoodAndUpdateBoxByTimestampAndBox(currentWeek[i],Hive.box(reducedStatisticsBoxName));
}
break;
case TimeSpan.month:
List<int> currentMonth = getTimestampsByTimestampAndTimespan(TimeSpan.month,timestamp);
for(int i = 0;i < currentMonth.length;i++){
getNewFoodAndUpdateReducedBoxByTimestamp(currentMonth[i]);
getNewFoodAndUpdateBoxByTimestampAndBox(currentMonth[i],Hive.box(reducedStatisticsBoxName));
}
break;
}
updateCalculationsAndNotfiyListeners();
updateCalculationsAndNotfiyListenersForPorgressStatistics();
}
void updateCalculationsAndNotfiyListeners(){
eatenCalories.value = getAllEatenCaloriesForTodayStatistics();
void updateCalculationsAndNotfiyListenersForPorgressStatistics(){
eatenCalories.value = getAllEatenCaloriesByBox(Hive.box(reducedStatisticsBoxName));
eatenCalories.notifyListeners();
ingredients.value = getAllEatenIngredientsForTodayStatistics();
ingredients.notifyListeners();
}
void getNewFoodAndUpdateReducedBoxByTimestamp(int timestamp){
void getNewFoodAndUpdateBoxByTimestampAndBox(int timestamp, Box box){
Map<String,List<Food>> newFood = getFoodMapForGivenTimestampFromMainBox(timestamp);
if(newFood.keys.isNotEmpty){
setElementsOfReducedBox(newFood);
setElementsOfBoxByBox(newFood, box);
}
}
@ -98,8 +105,7 @@ class StatisticsService {
}
}
setElementsOfReducedBox(Map<String,List<Food>> newFood){
Box box = Hive.box(reducedStatisticsBoxName);
setElementsOfBoxByBox(Map<String,List<Food>> newFood,Box box){
Iterable<String> keys = newFood.keys;
for(int i = 0; i < keys.length;i++){
List<Food> alreadyExisting = castDynamicToListFood(box.get(keys.elementAt(i)));
@ -187,8 +193,7 @@ class StatisticsService {
return randomTimestamp;
}
int getAllEatenCaloriesForTodayStatistics(){
Box box = Hive.box(reducedStatisticsBoxName);
int getAllEatenCaloriesByBox(Box box){
num sum = 0;
for(int i = 0; i < box.keys.length;i++){
for(Food food in box.get(box.keys.elementAt(i))){
@ -213,33 +218,50 @@ class StatisticsService {
return [fat as double,protein as double,carbs as double];
}
num getAllCaloriesByBoxAndTimestamp(Box box,int timestamp){
Map<String, List<Food>> valueMap = castDynamicMap(box.get(timestamp));
num sum = 0;
for(var mealType in valueMap.keys){
if(valueMap.containsKey(mealType)){
List<Food> values = valueMap[mealType]!;
for(var value in values){
sum += value.calories;
void updateCalculationsAndNotfiyListenersForTodayStatistics(){
dailyAverageForCurrentWeek.value = getAverageCaloriesForCurrentWeekOnDailyBasis();
dailyAverageForCurrentWeek.notifyListeners();
weeklyCaloryRanking.value = getWeeklyCaloryRanking();
weeklyCaloryRanking.notifyListeners();
}
void updateProgressBoxValues(){
Box box = Hive.box(progressStatisticsBoxName);
box.clear();
int timestamp = getTimestampFromNow();
List<int> currentWeek = getTimestampsByTimestampAndTimespan(TimeSpan.week,timestamp);
for(int i = 0;i < currentWeek.length;i++){
getNewFoodAndUpdateBoxByTimestampAndBox(currentWeek[i],box);
}
updateCalculationsAndNotfiyListenersForTodayStatistics();
}
int getAverageCaloriesForCurrentWeekOnDailyBasis(){
Box box = Hive.box(progressStatisticsBoxName);
return getAllEatenCaloriesByBox(box)~/7;
}
List<Food> getWeeklyCaloryRanking(){
int timestamp = getTimestampFromNow();
List<int> currentWeek = getTimestampsByTimestampAndTimespan(TimeSpan.week,timestamp);
List<Food> allFoodsOfWeek = [];
for(int i = 0;i < currentWeek.length;i++){
Map<String,List<Food>> foodFromMainBox = getFoodMapForGivenTimestampFromMainBox(currentWeek[i]);
Iterable<String> keys = foodFromMainBox.keys;
if(keys.isNotEmpty){
for(int i = 0; i < keys.length;i++ ){
allFoodsOfWeek.addAll(foodFromMainBox[keys.elementAt(i)] as Iterable<Food>);
}
}
}
return sum;
allFoodsOfWeek.sort((a, b) => b.calories - a.calories);
return getListOfDistinctElements(allFoodsOfWeek);
}
num getCaloriesByTimestampAndMealTypeAndBox(Box box,DateTime date, String mealType){
int timestamp = date.millisecondsSinceEpoch.toInt() ~/ 1000;
Map<String, List<Food>> valueMap = castDynamicMap(box.get(timestamp));
num sum = 0;
if(valueMap.containsKey(mealType)){
List<Food> values = valueMap[mealType]!;
for(var value in values){
sum += value.calories;
}
}
return sum;
getTimestampFromNow(){
DateTime now = DateTime.now();
return now.millisecondsSinceEpoch.toInt() ~/ 1000;
}
showItems(){
print("Statistics.dart - showItems() - ITEMS");
//Hive.box(boxName).clear();

View File

@ -26,6 +26,8 @@ class MainPageState extends State<MainPage> {
currentIndex = index;
if(currentIndex == 1){
StatisticsService.instance.updateReducedBoxByTimespan(TimeSpan.day);
}else if(currentIndex == 2){
StatisticsService.instance.updateProgressBoxValues();
}
pages[currentIndex];
});

View File

@ -1,9 +1,12 @@
import 'package:ernaehrung/android/components/meal_page_text/secondary_big_text_component.dart';
import 'package:ernaehrung/android/components/meal_page_text/secondary_text_component.dart';
import 'package:ernaehrung/android/components/meal_page_text/title_component.dart';
import 'package:ernaehrung/android/config/statistics.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import '../../config/format_helper.dart';
class ProgressPage extends StatelessWidget {
final String title;
final Color backgroundColor = const Color(0xff47a44b);
@ -28,109 +31,68 @@ class ProgressPage extends StatelessWidget {
padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 8),
child: Column(
children: [
Container(
height: 284,
decoration: BoxDecoration(
border: Border.all(),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const TitleComponent("Kalorien"),
const SizedBox(
height: 16,
ValueListenableBuilder(
valueListenable: StatisticsService.instance.dailyAverageForCurrentWeek,
builder: (context, value, child) {
return Container(
height: 284,
decoration: BoxDecoration(
border: Border.all(),
),
const SecondaryTextComponent("Durchschnittlich"),
SecondaryBigTextComponent(1235.toString()),
SizedBox(
height: 200,
child: BarChart(
BarChartData(
barTouchData: barTouchData,
titlesData: titlesData,
borderData: borderData,
barGroups: barGroups,
gridData: FlGridData(show: false),
alignment: BarChartAlignment.spaceAround,
maxY: 200,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const TitleComponent("Kalorien"),
const SizedBox(
height: 10,
),
),
)
],
),
const SecondaryTextComponent("Durchschnittlich"),
SecondaryBigTextComponent(value.toString()),
SizedBox(
height: 200,
child: BarChart(
BarChartData(
barTouchData: barTouchData,
titlesData: titlesData,
borderData: borderData,
barGroups: barGroups,
gridData: FlGridData(show: false),
alignment: BarChartAlignment.spaceAround,
maxY: 200,
),
),
)
],
),
);
},
),
ValueListenableBuilder(
valueListenable: StatisticsService.instance.weeklyCaloryRanking,
builder: (context, value, child) {
return Column(
//TODO: Loop through the values and display them dynamically
children: [
const TitleComponent("Lebensmittel mit dem höchsten Kaloriengehalt"),
const SizedBox(height: 24,),
for (var item in value.toSet())
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SecondaryTextComponent(getWeeklyRankingString(item.name)),
SecondaryTextComponent(item.calories.toString()),
],
),
],
);
},
),
Container(
margin: const EdgeInsets.symmetric(vertical: 16, horizontal: 0),
child: Column(
//TODO: Aussortieren und mit einer Schleife drüber gehen
//bzw. die Daten aus der Hivebox ziehen und sortieren
children: [
const TitleComponent(
"Lebensmittel mit dem höchsten Kaloriengehalt"),
const SizedBox(height: 24,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
SecondaryTextComponent("Haferflocker"),
SecondaryTextComponent("670 Kalorien"),
],
),
const SizedBox(height: 24,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
SecondaryTextComponent("Haferflocker"),
SecondaryTextComponent("670 Kalorien"),
],
),
const SizedBox(height: 24,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
SecondaryTextComponent("Haferflocker"),
SecondaryTextComponent("670 Kalorien"),
],
),
const SizedBox(height: 24,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
SecondaryTextComponent("Haferflocker"),
SecondaryTextComponent("670 Kalorien"),
],
),
const SizedBox(height: 24,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
SecondaryTextComponent("Haferflocker"),
SecondaryTextComponent("670 Kalorien"),
],
),
const SizedBox(height: 24,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
SecondaryTextComponent("Haferflocker"),
SecondaryTextComponent("670 Kalorien"),
],
),
const SizedBox(height: 24,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
SecondaryTextComponent("Haferflocker"),
SecondaryTextComponent("670 Kalorien"),
],
)
],
),
)
],
),
),
),
);
}
BarTouchData get barTouchData => BarTouchData(

View File

@ -18,6 +18,7 @@ void main() async {
//await Hive.deleteFromDisk();
await Hive.openBox('STATISTICS_REDUCED');
await Hive.openBox('STATISTICS_PROGRESS');
await Hive.openBox('STATISTICS_MAIN');
await Hive.openBox('TODAY');
setupTodayBox();