DataProvider.dart 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. import 'dart:async';
  2. import 'package:fl_chart/fl_chart.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter_habit/provider/ConfigProvider.dart';
  5. import 'package:flutter_habit/common/utils/ConvertUtils.dart';
  6. import 'package:flutter_habit/common/utils/VerificationUtils.dart';
  7. import 'package:flutter_habit/database/entity/BasicInfo.dart';
  8. import 'package:flutter_habit/database/entity/ExerciseInfo.dart';
  9. import 'package:flutter_habit/database/entity/FoodInfo.dart';
  10. import 'package:flutter_habit/database/entity/LifeInfo.dart';
  11. import 'package:flutter_habit/database/entity/ScheduledExercise.dart';
  12. import 'package:flutter_habit/database/entity/SportInfo.dart';
  13. import 'package:flutter_habit/database/entity/StudyInfo.dart';
  14. import 'package:flutter_habit/database/mapper/BasicInfoMapper.dart';
  15. import 'package:flutter_habit/database/mapper/ExerciseInfoMapper.dart';
  16. import 'package:flutter_habit/database/mapper/FoodInfoMapper.dart';
  17. import 'package:flutter_habit/database/mapper/LifeInfoMapper.dart';
  18. import 'package:flutter_habit/database/mapper/ScheduledExerciseMapper.dart';
  19. import 'package:flutter_habit/database/mapper/SportInfoMapper.dart';
  20. import 'package:flutter_habit/database/mapper/StudyInfoMapper.dart';
  21. class DataProvider extends ChangeNotifier {
  22. Future<void> init() async {
  23. await loadData();
  24. DateTime now = DateTime.now();
  25. Timer.periodic(
  26. ConvertUtils.dateOfDateTime(now)
  27. .add(Duration(days: 1, seconds: 1))
  28. .difference(now), (t) async {
  29. t.cancel();
  30. debugPrint("refresh");
  31. await loadData();
  32. Timer.periodic(Duration(days: 1), (t) async {
  33. debugPrint("refresh");
  34. await loadData();
  35. });
  36. });
  37. debugPrint("init DataProvider");
  38. }
  39. Future<void> loadData() async {
  40. await loadBasicInfoData();
  41. await loadLifeInfoData();
  42. await loadExerciseInfoData();
  43. await loadStudyInfoData();
  44. await evaluateToday();
  45. }
  46. // basic info
  47. double? height;
  48. double? weight;
  49. String? bmi;
  50. double? breastLine;
  51. double? waistLine;
  52. double? hipLine;
  53. List<FlSpot> weightFlSpots = [];
  54. int weightChartSize = 7;
  55. List<FlSpot> brestLineFlSpots = [];
  56. List<FlSpot> waistLineFlSpots = [];
  57. List<FlSpot> hipLineFlSpots = [];
  58. int bwhChartSize = 7;
  59. Future<void> loadBasicInfoData() async {
  60. int dateTime90daysAgo = ConvertUtils.dateOfDateTime(DateTime.now())
  61. .subtract(Duration(days: 90))
  62. .millisecondsSinceEpoch;
  63. // 基本信息
  64. List<BasicInfo> basicInfoList =
  65. (await BasicInfoMapper().selectWhere("date >= $dateTime90daysAgo"))!;
  66. height = null;
  67. weight = null;
  68. bmi = null;
  69. breastLine = null;
  70. waistLine = null;
  71. hipLine = null;
  72. // 基本数据
  73. if (basicInfoList.isNotEmpty) {
  74. height = basicInfoList.last.getHeight();
  75. weight = basicInfoList.last.getWeight();
  76. bmi = (weight! / height! / height! * 10000).toStringAsFixed(2);
  77. breastLine = basicInfoList.last.getBreastLine();
  78. waistLine = basicInfoList.last.getWaistLine();
  79. hipLine = basicInfoList.last.getHipLine();
  80. }
  81. // 将数据转为点
  82. weightFlSpots = [];
  83. brestLineFlSpots = [];
  84. waistLineFlSpots = [];
  85. hipLineFlSpots = [];
  86. basicInfoList.forEach((i) {
  87. // 换算为x.x天
  88. weightFlSpots.add(
  89. FlSpot(
  90. ConvertUtils.localDaysSinceEpoch(
  91. DateTime.fromMillisecondsSinceEpoch(i.getDate()!))
  92. .floorToDouble(),
  93. i.getWeight()!,
  94. ),
  95. );
  96. brestLineFlSpots.add(
  97. FlSpot(
  98. ConvertUtils.localDaysSinceEpoch(
  99. DateTime.fromMillisecondsSinceEpoch(i.getDate()!))
  100. .floorToDouble(),
  101. i.getBreastLine()!,
  102. ),
  103. );
  104. waistLineFlSpots.add(
  105. FlSpot(
  106. ConvertUtils.localDaysSinceEpoch(
  107. DateTime.fromMillisecondsSinceEpoch(i.getDate()!))
  108. .floorToDouble(),
  109. i.getWaistLine()!,
  110. ),
  111. );
  112. hipLineFlSpots.add(
  113. FlSpot(
  114. ConvertUtils.localDaysSinceEpoch(
  115. DateTime.fromMillisecondsSinceEpoch(i.getDate()!))
  116. .floorToDouble(),
  117. i.getHipLine()!,
  118. ),
  119. );
  120. });
  121. notifyListeners();
  122. }
  123. // life info
  124. int? lastNightSleepTime;
  125. double todayInjectKCal = 0;
  126. int todayProgress = 0;
  127. double todayMoney = 0;
  128. List<FlSpot> sleepTimeFlSpots = [];
  129. int sleepTimeChartSize = 7;
  130. List<FlSpot> injectKCalFlSpots = [];
  131. int injectKCalChartSize = 7;
  132. List<FlSpot> getUpTimeFlSpots = [];
  133. List<FlSpot> midRestTimeFlSpots = [];
  134. List<FlSpot> restTimeFlSpots = [];
  135. int timeChartSize = 7;
  136. List<FlSpot> progressFlSpots = [];
  137. int progressChartSize = 7;
  138. List<FlSpot> moneyFlSpots = [];
  139. int moneyChartSize = 7;
  140. List<FlSpot> eatBreakfastTimeFlSpots = [];
  141. List<FlSpot> eatLunchTimeFlSpots = [];
  142. List<FlSpot> eatDinnerTimeFlSpots = [];
  143. int eatTimeChartSize = 7;
  144. Future<void> loadLifeInfoData() async {
  145. int date91daysAgo = ConvertUtils.dateOfDateTime(DateTime.now())
  146. .subtract(Duration(days: 91))
  147. .millisecondsSinceEpoch;
  148. // 日常生活
  149. List<LifeInfo> lifeInfoList =
  150. (await LifeInfoMapper().selectWhere("date >= $date91daysAgo"))!;
  151. List<FoodInfo>? foodInfoList = await FoodInfoMapper().selectAll();
  152. // 构造点、数据
  153. sleepTimeFlSpots = [];
  154. injectKCalFlSpots = [];
  155. progressFlSpots = [];
  156. getUpTimeFlSpots = [];
  157. midRestTimeFlSpots = [];
  158. restTimeFlSpots = [];
  159. moneyFlSpots = [];
  160. eatBreakfastTimeFlSpots = [];
  161. eatLunchTimeFlSpots = [];
  162. eatDinnerTimeFlSpots = [];
  163. todayInjectKCal = 0;
  164. todayProgress = 0;
  165. todayMoney = 0;
  166. lastNightSleepTime = null;
  167. if (lifeInfoList.isNotEmpty) {
  168. for (int i = 0; i < lifeInfoList.length; i++) {
  169. LifeInfo lastLifeInfo = i == 0 ? LifeInfo() : lifeInfoList[i - 1];
  170. LifeInfo currLifeInfo = lifeInfoList[i];
  171. // 准备数据
  172. int date = currLifeInfo.getDate()!;
  173. int? lastDate = lastLifeInfo.getDate();
  174. int? sleepTime;
  175. if (lastLifeInfo.getRestTime() != null &&
  176. currLifeInfo.getGetUpTime() != null) {
  177. sleepTime = currLifeInfo.getGetUpTime()! - lastLifeInfo.getRestTime()!;
  178. }
  179. lastNightSleepTime = sleepTime;
  180. double totalCal = 0;
  181. if (currLifeInfo.getBreakfastQuantity() != null) {
  182. FoodInfo currBreakfastInfo = foodInfoList!.firstWhere(
  183. (test) => test.getId() == currLifeInfo.getBreakfastId());
  184. totalCal += currBreakfastInfo.getHgkCalorie()! *
  185. currLifeInfo.getBreakfastQuantity()!;
  186. }
  187. if (currLifeInfo.getLunchQuantity() != null) {
  188. FoodInfo currLunchInfo = foodInfoList!
  189. .firstWhere((test) => test.getId() == currLifeInfo.getLunchId());
  190. totalCal +=
  191. currLunchInfo.getHgkCalorie()! * currLifeInfo.getLunchQuantity()!;
  192. }
  193. if (currLifeInfo.getDinnerQuantity() != null) {
  194. FoodInfo currDinnerInfo = foodInfoList!
  195. .firstWhere((test) => test.getId() == currLifeInfo.getDinnerId());
  196. totalCal +=
  197. currDinnerInfo.getHgkCalorie()! * currLifeInfo.getDinnerQuantity()!;
  198. }
  199. todayInjectKCal = totalCal;
  200. int progress = 0;
  201. ConfigProvider configProvider = ConfigProvider();
  202. configProvider.load();
  203. progress += currLifeInfo.getGetUpTime() == null
  204. ? 0
  205. : VerifyUtils.isBetweenTime(configProvider.getUpTimeStart,
  206. currLifeInfo.getGetUpTime()!, configProvider.getUpTimeEnd)
  207. ? 2
  208. : 1;
  209. progress += currLifeInfo.getBreakfastTime() == null
  210. ? 0
  211. : VerifyUtils.isBetweenTime(
  212. configProvider.breakfastTimeStart,
  213. currLifeInfo.getBreakfastTime()!,
  214. configProvider.breakfastTimeEnd)
  215. ? 2
  216. : 1;
  217. progress += currLifeInfo.getLunchTime() == null
  218. ? 0
  219. : VerifyUtils.isBetweenTime(configProvider.lunchTimeStart,
  220. currLifeInfo.getLunchTime()!, configProvider.lunchTimeEnd)
  221. ? 2
  222. : 1;
  223. progress += currLifeInfo.getMidRestTime() == null
  224. ? 0
  225. : VerifyUtils.isBetweenTime(
  226. configProvider.midRestTimeStart,
  227. currLifeInfo.getMidRestTime()!,
  228. configProvider.midRestTimeEnd)
  229. ? 2
  230. : 1;
  231. progress += currLifeInfo.getDinnerTime() == null
  232. ? 0
  233. : VerifyUtils.isBetweenTime(configProvider.dinnerTimeStart,
  234. currLifeInfo.getDinnerTime()!, configProvider.dinnerTimeEnd)
  235. ? 2
  236. : 1;
  237. progress += currLifeInfo.getRestTime() == null
  238. ? 0
  239. : VerifyUtils.isBetweenTime(configProvider.restTimeStart,
  240. currLifeInfo.getRestTime()!, configProvider.restTimeEnd)
  241. ? 2
  242. : 1;
  243. todayProgress = progress;
  244. // 构造点
  245. if (lastDate != null && lastNightSleepTime != null) {
  246. sleepTimeFlSpots.add(FlSpot(
  247. ConvertUtils.localDaysSinceEpoch(
  248. DateTime.fromMillisecondsSinceEpoch(lastDate))
  249. .floorToDouble(),
  250. ConvertUtils.fixedDouble(
  251. ConvertUtils.hourFormMilliseconds(lastNightSleepTime!), 2)));
  252. }
  253. injectKCalFlSpots.add(FlSpot(
  254. ConvertUtils.localDaysSinceEpoch(
  255. DateTime.fromMillisecondsSinceEpoch(date))
  256. .floorToDouble(),
  257. ConvertUtils.fixedDouble(totalCal, 2)));
  258. progressFlSpots.add(FlSpot(
  259. ConvertUtils.localDaysSinceEpoch(
  260. DateTime.fromMillisecondsSinceEpoch(date))
  261. .floorToDouble(),
  262. ConvertUtils.fixedDouble(progress / 12, 2)));
  263. if (currLifeInfo.getGetUpTime() != null) {
  264. getUpTimeFlSpots.add(FlSpot(
  265. ConvertUtils.localDaysSinceEpoch(
  266. DateTime.fromMillisecondsSinceEpoch(date))
  267. .floorToDouble(),
  268. 24 -
  269. ConvertUtils.hourFormMillisecondsSinceEpoch(
  270. currLifeInfo.getGetUpTime()!)));
  271. }
  272. if (currLifeInfo.getMidRestTime() != null) {
  273. midRestTimeFlSpots.add(FlSpot(
  274. ConvertUtils.localDaysSinceEpoch(
  275. DateTime.fromMillisecondsSinceEpoch(date))
  276. .floorToDouble(),
  277. 24 -
  278. ConvertUtils.hourFormMillisecondsSinceEpoch(
  279. currLifeInfo.getMidRestTime()!)));
  280. }
  281. if (currLifeInfo.getRestTime() != null) {
  282. restTimeFlSpots.add(FlSpot(
  283. ConvertUtils.localDaysSinceEpoch(
  284. DateTime.fromMillisecondsSinceEpoch(date))
  285. .floorToDouble(),
  286. 24 -
  287. ConvertUtils.hourFormMillisecondsSinceEpoch(
  288. currLifeInfo.getRestTime()!)));
  289. }
  290. if (currLifeInfo.getBreakfastTime() != null) {
  291. eatBreakfastTimeFlSpots.add(FlSpot(
  292. ConvertUtils.localDaysSinceEpoch(
  293. DateTime.fromMillisecondsSinceEpoch(date))
  294. .floorToDouble(),
  295. 24 -
  296. ConvertUtils.hourFormMillisecondsSinceEpoch(
  297. currLifeInfo.getBreakfastTime()!)));
  298. }
  299. if (currLifeInfo.getLunchTime() != null) {
  300. eatLunchTimeFlSpots.add(FlSpot(
  301. ConvertUtils.localDaysSinceEpoch(
  302. DateTime.fromMillisecondsSinceEpoch(date))
  303. .floorToDouble(),
  304. 24 -
  305. ConvertUtils.hourFormMillisecondsSinceEpoch(
  306. currLifeInfo.getLunchTime()!)));
  307. }
  308. if (currLifeInfo.getDinnerTime() != null) {
  309. eatDinnerTimeFlSpots.add(FlSpot(
  310. ConvertUtils.localDaysSinceEpoch(
  311. DateTime.fromMillisecondsSinceEpoch(date))
  312. .floorToDouble(),
  313. 24 -
  314. ConvertUtils.hourFormMillisecondsSinceEpoch(
  315. currLifeInfo.getDinnerTime()!)));
  316. }
  317. double totalMoney = 0;
  318. totalMoney += currLifeInfo.getBreakfastMoney() ?? 0;
  319. totalMoney += currLifeInfo.getLunchMoney() ?? 0;
  320. totalMoney += currLifeInfo.getDinnerMoney() ?? 0;
  321. moneyFlSpots.add(FlSpot(
  322. ConvertUtils.localDaysSinceEpoch(
  323. DateTime.fromMillisecondsSinceEpoch(date))
  324. .floorToDouble(),
  325. ConvertUtils.fixedDouble(totalMoney, 2)));
  326. todayMoney = totalMoney;
  327. }
  328. }
  329. notifyListeners();
  330. }
  331. int sevenDayExerciseTimes = 0;
  332. double sevenDayExerciseTotalKCal = 0;
  333. int scheduledExerciseCount = 0;
  334. List<MapEntry<ScheduledExercise, SportInfo>> scheduledExerciseSportInfoList =
  335. [];
  336. List<FlSpot> exerciseInfoFlSpots = [];
  337. int exerciseInfoChartSize = 7;
  338. Future<void> loadExerciseInfoData() async {
  339. int date90daysAgo = ConvertUtils.dateOfDateTime(DateTime.now())
  340. .subtract(Duration(days: 90))
  341. .millisecondsSinceEpoch;
  342. int date7daysAgo = ConvertUtils.dateOfDateTime(DateTime.now())
  343. .subtract(Duration(days: 7))
  344. .millisecondsSinceEpoch;
  345. List<ExerciseInfo> exerciseInfoList = (await ExerciseInfoMapper()
  346. .selectWhere("exerciseTime >= $date90daysAgo"))!;
  347. List<ExerciseInfo> sevenDayExerciseInfoList =
  348. (await ExerciseInfoMapper().selectWhere("exerciseTime >= $date7daysAgo"))!;
  349. List<ScheduledExercise> schedules =
  350. (await ScheduledExerciseMapper().selectAll())!;
  351. List<SportInfo>? sports = await SportInfoMapper().selectAll();
  352. scheduledExerciseSportInfoList = schedules.map((i) {
  353. return MapEntry(
  354. i, sports!.firstWhere((test) => test.getId() == i.getSportId()));
  355. }).toList();
  356. // 卡
  357. scheduledExerciseCount = schedules.length;
  358. sevenDayExerciseTimes = sevenDayExerciseInfoList.length;
  359. sevenDayExerciseTotalKCal = 0;
  360. sevenDayExerciseInfoList.forEach((i) {
  361. sevenDayExerciseTotalKCal += i.getExerciseQuantity()! *
  362. sports!
  363. .firstWhere((test) => test.getId() == i.getSportId())
  364. .getHkCalorie()!;
  365. });
  366. // 表
  367. exerciseInfoFlSpots = [];
  368. Map<int, double> temp = {};
  369. exerciseInfoList.forEach((i) {
  370. int currDay = ConvertUtils.localDaysSinceEpoch(
  371. DateTime.fromMillisecondsSinceEpoch(i.getExerciseTime()!))
  372. .floor();
  373. if (temp[currDay] == null) {
  374. temp[currDay] = i.getExerciseQuantity()! *
  375. sports!
  376. .firstWhere((test) => test.getId() == i.getSportId())
  377. .getHkCalorie()!;
  378. } else {
  379. temp[currDay] += i.getExerciseQuantity()! *
  380. sports!
  381. .firstWhere((test) => test.getId() == i.getSportId())
  382. .getHkCalorie()!;
  383. }
  384. });
  385. temp.forEach((k, v) {
  386. exerciseInfoFlSpots
  387. .add(FlSpot(k.toDouble(), ConvertUtils.fixedDouble(v, 2)));
  388. });
  389. notifyListeners();
  390. }
  391. int lateTimes = 0;
  392. int absentTimes = 0;
  393. int unSolveTroubles = 0;
  394. int unDoneHomeWorks = 0;
  395. List<StudyInfo> unSolveStudyInfoList = [];
  396. List<FlSpot> dailyStudyCountFlSpots = [];
  397. int dailyStudyCountChartSize = 7;
  398. Future<void> loadStudyInfoData() async {
  399. int date90daysAgo = ConvertUtils.dateOfDateTime(DateTime.now())
  400. .subtract(Duration(days: 90))
  401. .millisecondsSinceEpoch;
  402. List<StudyInfo> studyInfoList =
  403. (await StudyInfoMapper().selectWhere("date >= $date90daysAgo"))!;
  404. List<StudyInfo> lateList =
  405. (await StudyInfoMapper().selectWhere("isLate = 1"))!;
  406. List<StudyInfo> absentList =
  407. (await StudyInfoMapper().selectWhere("isAbsent = 1"))!;
  408. List<StudyInfo> unSolveTroublesAndUnDoneHomeList = (await StudyInfoMapper()
  409. .selectWhere("isTroublesSolved = 0 or isHomeWorkDone == 0"))!;
  410. lateTimes = 0;
  411. absentTimes = 0;
  412. unSolveTroubles = 0;
  413. unDoneHomeWorks = 0;
  414. lateTimes = lateList.length;
  415. absentTimes = absentList.length;
  416. unSolveStudyInfoList = [];
  417. unSolveTroubles = 0;
  418. unDoneHomeWorks = 0;
  419. unSolveTroublesAndUnDoneHomeList.forEach((i) {
  420. unSolveStudyInfoList.add(i);
  421. if (i.getIsHomeWorkDone() == 0) {
  422. unDoneHomeWorks++;
  423. }
  424. if (i.getIsTroublesSolved() == 0) {
  425. unSolveTroubles++;
  426. }
  427. });
  428. dailyStudyCountFlSpots = [];
  429. Map<int, int> temp = {};
  430. studyInfoList.forEach((i) {
  431. int currDay = ConvertUtils.localDaysSinceEpoch(
  432. DateTime.fromMillisecondsSinceEpoch(i.getDate()!))
  433. .floor();
  434. if (temp[currDay] == null) {
  435. temp[currDay] = 1;
  436. } else {
  437. temp[currDay] += 1;
  438. }
  439. });
  440. temp.forEach((key, value) {
  441. dailyStudyCountFlSpots.add(FlSpot(key.toDouble(), value.toDouble()));
  442. });
  443. notifyListeners();
  444. }
  445. int todayEvaluate = 0;
  446. Future<void> evaluateToday() async {
  447. // 0 - 15
  448. todayEvaluate = 0;
  449. todayEvaluate += todayProgress;
  450. int todayZeroTime =
  451. ConvertUtils.dateOfDateTime(DateTime.now()).millisecondsSinceEpoch;
  452. List<BasicInfo> l1 =
  453. (await BasicInfoMapper().selectWhere("date >= $todayZeroTime"))!;
  454. if (l1.isNotEmpty) {
  455. todayEvaluate++;
  456. }
  457. List<ExerciseInfo> l2 =
  458. (await ExerciseInfoMapper().selectWhere("exerciseTime >= $todayZeroTime"))!;
  459. if (l2.isNotEmpty) {
  460. todayEvaluate++;
  461. }
  462. List<StudyInfo> l3 =
  463. (await StudyInfoMapper().selectWhere("date >= $todayZeroTime"))!;
  464. if (l3.isNotEmpty) {
  465. todayEvaluate++;
  466. }
  467. notifyListeners();
  468. }
  469. }