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}