Optimize Loading times

This commit is contained in:
Sewmina
2022-04-15 05:51:39 +05:30
parent 17340890ed
commit 39a9a66f56
5 changed files with 493 additions and 95 deletions

182
lib/Analytics.dart Normal file
View File

@@ -0,0 +1,182 @@
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart';
import 'package:tasktracker/AvgDay.dart';
import 'package:tasktracker/main.dart';
import 'Data.dart';
import 'DebugHelper.dart';
import 'User.dart' as User;
class AnalyticsPage extends StatefulWidget {
const AnalyticsPage({Key? key}) : super(key: key);
@override
State<AnalyticsPage> createState() => _AnalyticsPageState();
}
class _AnalyticsPageState extends State<AnalyticsPage> {
@override
Widget build(BuildContext context) {
// for (var value in avgActs) {
// Debug.LogResponse('${value.taskType.name} : ${DateFormat('HH:mm').format(value.startTime)} - ${DateFormat('HH:mm').format(value.endTime)}');
// }
return Scaffold(
appBar: AppBar(title: Row(
children: [FaIcon(FontAwesomeIcons.chartLine),SizedBox(width: 15,), Text("Analytics")],
)),
drawer: navDrawer(context, 1),
body: Container(
padding: EdgeInsets.all(8),
child:Column(
children: [
Card(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 15, vertical: 5),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Average Day',style: TextStyle(fontSize: 17)),
MaterialButton(
color: Colors.green,
onPressed: (){
Navigator.of(context).push(MaterialPageRoute(builder: (context)=> AvgDayPage()));
},
child: Text('More...'),
)
],
),
Divider(),
],
),
)
)
],
)
)
);
}
}
class AnalyticTools{
static double dailyThreshold = 0.9;
static int activityGroupingThreshold = 4;
static List<Activity> getAverageDayActs(DateTimeRange range){
int totalDays = range.end.difference(range.start).inDays;
Map<TaskType, List<AvgActData>> avgActs = <TaskType, List<AvgActData>>{};
Map<TaskType, List<DateTimeRange>> acts = <TaskType, List<DateTimeRange>>{};
List<Activity> listToReturn = [];
//PASS 1: Split Activities and mark their time range
User.activities.forEach((element) {
if(element.startTime.isAfter(range.start) && element.endTime.isBefore(range.end)){
//Eligible activity to calculate
if(acts.containsKey(element.taskType)){
acts[element.taskType]!.add(DateTimeRange(start: element.startTime, end: element.endTime));
}else{
acts.putIfAbsent(element.taskType, () => [DateTimeRange(start: element.startTime, end: element.endTime)]);
}
}
});
Debug.Log('Analysing ${acts.length} activities');
//PASS 2: Calculate avg Time Range for each Activity
acts.forEach((key, value) {
if(value.length < totalDays * dailyThreshold){
//Not a frequent Activity,
}else{
//Iterate through the time ranges of this activity
for (var _actTime in value) {
DateTime _start = DateTime(0,0,0,_actTime.start.hour, _actTime.start.minute);
DateTime _end = DateTime(0,0,0,_actTime.end.hour, _actTime.end.minute);
if(_start.isAfter(_end)){Debug.LogError('${key.name} start after end? : $_start, $_end'); continue;}
DateTimeRange actTime = DateTimeRange(start: _start, end: _end);
if(!avgActs.containsKey(key)){
avgActs.putIfAbsent(key, () => []);
}
if(avgActs[key]!.isEmpty){
//No need to check groups. No groups exists.
avgActs[key]!.add(AvgActData(actTime, 1, 1));
}else{
//Check for the closest time group
bool foundGroup = false;
for(int i = 0; i < avgActs[key]!.length; i++){
if(foundGroup){continue;}
DateTimeRange avgTime = avgActs[key]![i].avgRange;
int count = avgActs[key]![i].count;
if(actTime.start.difference(avgTime.start).inHours.abs() < activityGroupingThreshold && actTime.end.difference(avgTime.end).inHours.abs() < activityGroupingThreshold){
foundGroup = true;
int curStartMin = (avgTime.start.hour * 60) + avgTime.start.minute;
int curEndMin = (avgTime.end.hour * 60) + avgTime.end.minute;
int newStartMin = (actTime.start.hour * 60) + actTime.start.minute;
int newEndMin = (actTime.end.hour * 60) + actTime.end.minute;
int avgStartMin = ((curStartMin + newStartMin)/2).toInt();
int avgEndMin = ((curEndMin + newEndMin)/2).toInt();
Debug.Log('Avged : ${key.name} [$i] : ${avgStartMin} - ${avgEndMin}');
if(avgStartMin > avgEndMin){
//Malfunctioned
Debug.LogError('Start is after End? Wut???\nAvged : ${key.name}[$i] : ${avgStartMin} - ${avgEndMin}');
}else {
DateTime baseline = DateTime(0, 0, 0, 0, 0);
// avgActs[key]!.keys.toList()[i] =
// DateTimeRange(start: baseline.add(Duration(minutes: avgStartMin)), end: baseline.add(Duration(minutes: avgEndMin)));
// avgActs[key]!.values.toList()[i]++;
//avgActs[key]!.removeWhere((key, value) => key==avgTime);
avgActs[key]![i].avgRange = DateTimeRange(start: baseline.add(Duration(minutes: avgStartMin)), end: baseline.add(Duration(minutes: avgEndMin)));
avgActs[key]![i].count++;
}
break;
}
}
if(!foundGroup){
avgActs[key]!.add(AvgActData(actTime, 1, 1));
}
}
}
}
});
//PASS 3: Prepare the Activity list to return
avgActs.forEach((key, value) {
value.sort((a,b) => b.count.compareTo(a.count));
value.forEach((element) {
Activity thisAct = Activity(key, element.avgRange.start, element.avgRange.end);
Debug.LogResponse(
'${thisAct.taskType.name} (${element.count}) -> (${element.dailyCountAvg}) : ${DateFormat('HH:mm').format(thisAct.startTime)} - ${DateFormat('HH:mm').format(
thisAct.endTime)}');
if(element.count < totalDays * dailyThreshold/2){
Debug.Log('Ignoring due to DailyThreshold, ${element.count} < ${totalDays * dailyThreshold/2}');
}else {
listToReturn.add(thisAct);
}
});
// value.forEach((act, count) {
//
// });
});
return listToReturn;
}
}
class AvgActData{
AvgActData(this.avgRange, this.count, this.dailyCountAvg);
DateTimeRange avgRange;
int count;
double dailyCountAvg;
}