main
1import 'package:blood_pressure_app/features/statistics/value_distribution.dart';
2import 'package:blood_pressure_app/model/storage/settings_store.dart';
3import 'package:collection/collection.dart';
4import 'package:flutter/material.dart';
5import 'package:blood_pressure_app/l10n/app_localizations.dart';
6import 'package:health_data_store/health_data_store.dart';
7import 'package:provider/provider.dart';
8
9/// Viewer for [ValueDistribution]s from [BloodPressureRecord]s.
10///
11/// Displays a tab bar with different value distributions for available sys, dia
12/// and pul values from [BloodPressureRecord]s.
13class BloodPressureDistribution extends StatefulWidget {
14 /// Create a [ValueDistribution] viewer of the data of measurements.
15 const BloodPressureDistribution({
16 super.key,
17 required this.records,
18 });
19
20 /// All records to include in statistics computations.
21 ///
22 /// When a records includes null values, those values are left out for
23 /// computing this statistic. This means that no filtering of passed records
24 /// is required.
25 final Iterable<BloodPressureRecord> records;
26
27 @override
28 State<BloodPressureDistribution> createState() =>
29 _BloodPressureDistributionState();
30}
31
32class _BloodPressureDistributionState extends State<BloodPressureDistribution>
33 with TickerProviderStateMixin {
34
35 late final TabController _controller;
36
37 @override
38 void initState() {
39 super.initState();
40 _controller = TabController(length: 3, vsync: this);
41 _controller.addListener(() => setState((){}));
42 }
43
44 @override
45 void dispose() {
46 _controller.dispose();
47 super.dispose();
48 }
49
50 @override
51 Widget build(BuildContext context) {
52 final localizations = AppLocalizations.of(context)!;
53 return Column(
54 mainAxisSize: MainAxisSize.min,
55 children: [
56 DecoratedBox(
57 decoration: BoxDecoration(
58 color: Theme.of(context).cardColor,
59 borderRadius: BorderRadius.circular(50),
60 ),
61 child: TabBar.secondary(
62 labelPadding: const EdgeInsets.symmetric(vertical: 16),
63 indicator: BoxDecoration(
64 color: switch(_controller.index) {
65 0 => context.watch<Settings>().sysColor,
66 1 => context.watch<Settings>().diaColor,
67 2 => context.watch<Settings>().pulColor,
68 _ => Theme.of(context).colorScheme.primaryContainer,
69 },
70 borderRadius: BorderRadius.circular(50),
71 ),
72 dividerHeight: 0,
73 controller: _controller,
74 tabs: [
75 Text(localizations.sysLong),
76 Text(localizations.diaLong),
77 Text(localizations.pulLong),
78 ],
79 ),
80 ),
81 Expanded(
82 child: TabBarView(
83 controller: _controller,
84 children: [
85 // Preferred pressure unit can be ignored as values are relative.
86 ValueDistribution(
87 key: const Key('sys-dist'),
88 values: widget.records.map((e) => e.sys?.mmHg).whereNotNull(),
89 color: context.select<Settings, Color>((s) => s.sysColor),
90 ),
91 ValueDistribution(
92 key: const Key('dia-dist'),
93 values: widget.records.map((e) => e.dia?.mmHg).whereNotNull(),
94 color: context.select<Settings, Color>((s) => s.diaColor),
95 ),
96 ValueDistribution(
97 key: const Key('pul-dist'),
98 values: widget.records.map((e) => e.pul).whereNotNull(),
99 color: context.select<Settings, Color>((s) => s.pulColor),
100 ),
101 ],
102 ),
103 ),
104 ],
105 );
106 }
107
108}