main
  1import 'package:blood_pressure_app/components/nullable_text.dart';
  2import 'package:blood_pressure_app/components/pressure_text.dart';
  3import 'package:blood_pressure_app/data_util/entry_context.dart';
  4import 'package:blood_pressure_app/features/input/forms/add_entry_form.dart';
  5import 'package:blood_pressure_app/model/storage/settings_store.dart';
  6import 'package:flutter/material.dart';
  7import 'package:blood_pressure_app/l10n/app_localizations.dart';
  8import 'package:health_data_store/health_data_store.dart';
  9import 'package:intl/intl.dart';
 10import 'package:provider/provider.dart';
 11
 12/// A more compact [BloodPressureRecord] list that is less verbose.
 13class CompactMeasurementList extends StatefulWidget {
 14  /// Create a more compact, less verbose measurement list.
 15  const CompactMeasurementList({super.key,
 16    required this.data,
 17  });
 18
 19  /// Entries sorted with newest ordered first.
 20  final List<FullEntry> data;
 21
 22  @override
 23  State<CompactMeasurementList> createState() => _CompactMeasurementListState();
 24}
 25
 26class _CompactMeasurementListState extends State<CompactMeasurementList> {
 27  List<int> _tableElementsSizes = [33, 9, 9, 9, 30];
 28  int _sideFlex = 1;
 29  late DateFormat formatter;
 30
 31  @override
 32  void initState() {
 33    super.initState();
 34    formatter = DateFormat('yyyy-MM-dd HH:mm');
 35  }
 36
 37  Widget _buildHeader() => Row(
 38    children: [
 39      Expanded(
 40        flex: _sideFlex,
 41        child: const SizedBox(),
 42      ),
 43      Expanded(
 44        flex: _tableElementsSizes[0],
 45        child: Text(AppLocalizations.of(context)!.time, style: const TextStyle(fontWeight: FontWeight.bold)),),
 46      Expanded(
 47        flex: _tableElementsSizes[1],
 48        child: Text(AppLocalizations.of(context)!.sysShort,
 49          style: TextStyle(fontWeight: FontWeight.bold, color: context.select<Settings, Color>((s) => s.sysColor))),),
 50      Expanded(
 51        flex: _tableElementsSizes[2],
 52        child: Text(AppLocalizations.of(context)!.diaShort,
 53          style: TextStyle(fontWeight: FontWeight.bold, color: context.select<Settings, Color>((s) => s.diaColor))),),
 54      Expanded(
 55        flex: _tableElementsSizes[3],
 56        child: Text(AppLocalizations.of(context)!.pulShort,
 57          style: TextStyle(fontWeight: FontWeight.bold, color: context.select<Settings, Color>((s) => s.pulColor))),),
 58      Expanded(
 59        flex: _tableElementsSizes[4],
 60        child: Text(AppLocalizations.of(context)!.notes, style: const TextStyle(fontWeight: FontWeight.bold)),),
 61      Expanded(
 62        flex: _sideFlex,
 63        child: const SizedBox(),
 64      ),
 65    ],
 66  );
 67
 68  Widget _itemBuilder(BuildContext context, int index) => Column(
 69    children: [
 70      Dismissible(
 71        key: Key(widget.data[index].time.toIso8601String()),
 72        confirmDismiss: (direction) async {
 73          if (direction == DismissDirection.startToEnd) { // edit
 74            await context.createEntry(widget.data[index].asAddEntry);
 75            return false;
 76          } else { // delete
 77            await context.deleteEntry(widget.data[index]);
 78            return false;
 79          }
 80        },
 81        onDismissed: (direction) {},
 82        background: Container(
 83          width: 10,
 84          decoration:
 85          BoxDecoration(color: Colors.blue, borderRadius: BorderRadius.circular(5)),
 86          child: const Align(alignment: Alignment(-0.95, 0), child: Icon(Icons.edit)),
 87        ),
 88        secondaryBackground: Container(
 89          width: 10,
 90          decoration:
 91          BoxDecoration(color: Colors.red, borderRadius: BorderRadius.circular(5)),
 92          child: const Align(alignment: Alignment(0.95, 0), child: Icon(Icons.delete)),
 93        ),
 94        child: Container(
 95          constraints: const BoxConstraints(minHeight: 40),
 96          child: Row(children: [
 97            Expanded(
 98              flex: _sideFlex,
 99              child: const SizedBox(),
100            ),
101            Expanded(
102              flex: _tableElementsSizes[0],
103              child: Text(formatter.format(widget.data[index].time)),),
104            Expanded(
105                flex: _tableElementsSizes[1],
106                child: PressureText(widget.data[index].sys)),
107            Expanded(
108              flex: _tableElementsSizes[2],
109              child: PressureText(widget.data[index].dia),),
110            Expanded(
111              flex: _tableElementsSizes[3],
112              child: NullableText(widget.data[index].pul?.toString()),),
113            Expanded(
114              flex: _tableElementsSizes[4],
115              child: NullableText(() {
116                String note = widget.data[index].note ?? '';
117                for (final i in widget.data[index].intakes) {
118                  note += '${i.medicine.designation}(${i.dosis.mg}mg)';
119                }
120                return note.isEmpty ? null : note;
121              }()),
122            ),
123            Expanded(
124              flex: _sideFlex,
125              child: const SizedBox(),
126            ),
127          ],),
128        ),
129      ),
130      const Divider(
131        thickness: 1,
132        height: 1,
133      ),
134    ],
135  );
136
137  @override
138  Widget build(BuildContext context) {
139    formatter = DateFormat(context.select<Settings, String>((s) => s.dateFormatString));
140    if (MediaQuery.of(context).size.width < 1000) {
141      _tableElementsSizes = [33, 9, 9, 9, 30];
142      _sideFlex = 1;
143    } else {
144      _tableElementsSizes = [20, 5, 5, 5, 60];
145      _sideFlex = 5;
146    }
147    return Column(
148      children: [
149        _buildHeader(),
150        const SizedBox(
151          height: 10,
152        ),
153        Divider(
154          height: 0,
155          thickness: 2,
156          color: Theme.of(context).colorScheme.primaryContainer,
157        ),
158        Expanded(
159          child: Builder(
160            builder: (BuildContext context) {
161              if (widget.data.isEmpty) return Text(AppLocalizations.of(context)!.errNoData);
162              return ListView.builder(
163                itemCount: widget.data.length,
164                shrinkWrap: true,
165                padding: const EdgeInsets.all(2),
166                itemBuilder: _itemBuilder,
167              );
168            },
169          ),
170        ),
171      ],
172    );
173  }
174}