Commit 1c4ea25
Changed files (2)
lib
components
dialoges
screens
subsettings
export_import
lib/components/dialoges/import_preview.dart
@@ -1,13 +1,19 @@
import 'dart:math';
+import 'package:blood_pressure_app/components/custom_banner.dart';
import 'package:blood_pressure_app/components/dialoges/fullscreen_dialoge.dart';
+import 'package:blood_pressure_app/model/blood_pressure/record.dart';
import 'package:blood_pressure_app/model/export_import/column.dart';
import 'package:blood_pressure_app/model/export_import/csv_record_parsing_actor.dart';
import 'package:blood_pressure_app/model/storage/export_columns_store.dart';
import 'package:flutter/material.dart';
+import 'package:flutter/scheduler.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
+/// A preview that allows customizing columns used for csv data import.
+///
+/// Pops the scope with a list of measurements on save ([List<BloodPressureRecord>?]).
class ImportPreview extends StatefulWidget {
/// Create a preview of how the app would import csv with options.
const ImportPreview({super.key,
@@ -34,16 +40,52 @@ class _ImportPreviewState extends State<ImportPreview> {
late CsvRecordParsingActor _actor;
+ late final ScaffoldMessengerState messenger = ScaffoldMessenger.of(context);
+
+ bool _showingError = false;
+
@override
void initState() {
super.initState();
_actor = widget.initialActor;
+ SchedulerBinding.instance.addPostFrameCallback((_) => _updateBanner());
+ }
+
+ void _updateBanner() {
+ if (_showingError) {
+ _showingError = false;
+ messenger.removeCurrentMaterialBanner();
+ }
+ final err = _actor.attemptParse().error;
+ if (err != null) {
+ final localizations = AppLocalizations.of(context)!;
+ messenger.showMaterialBanner(CustomBanner(
+ content: Text(err.localize(localizations),
+ style: TextStyle(color: Theme.of(context).colorScheme.error),),
+ ),);
+ _showingError = true;
+ }
+ }
+
+ @override
+ void dispose() {
+ if(_showingError) {
+ SchedulerBinding.instance.addPostFrameCallback(
+ // TODO: add on close hook to dialoge and remove anti-pattern
+ (_) => messenger.removeCurrentMaterialBanner(),);
+ }
+ super.dispose();
}
@override
Widget build(BuildContext context) => FullscreenDialoge(
actionButtonText: AppLocalizations.of(context)!.import,
bottomAppBar: widget.bottomAppBar,
+ onActionButtonPressed: (_showingError) ? null : () {
+ final result = _actor.attemptParse();
+ if (result.hasError()) return;
+ Navigator.pop<List<BloodPressureRecord>>(context, result.getOr((e) => null));
+ },
body: SingleChildScrollView(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
@@ -54,7 +96,7 @@ class _ImportPreviewState extends State<ImportPreview> {
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
- DropdownButton(
+ DropdownButton( // TODO: show original column name
items: [
DropdownMenuItem(
child: Text(
@@ -68,7 +110,7 @@ class _ImportPreviewState extends State<ImportPreview> {
DropdownMenuItem(
value: parser,
child: Padding(
- padding: EdgeInsets.only(top: 8),
+ padding: const EdgeInsets.only(top: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -85,6 +127,7 @@ class _ImportPreviewState extends State<ImportPreview> {
setState(() {
_actor.changeColumnParser(_actor.columnNames[colIdx], parser);
});
+ _updateBanner();
},
),
const Divider(),
@@ -99,8 +142,8 @@ class _ImportPreviewState extends State<ImportPreview> {
alignment: AlignmentDirectional.center,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10),
- child: Text('...')
- )
+ child: Text('...'),
+ ),
),
],
),
@@ -141,3 +184,22 @@ class _ImportPreviewState extends State<ImportPreview> {
);
}
}
+
+// TODO: add setting for row limiting to make errors actionable
+
+/// Shows a dialoge to preview import of a csv file
+Future<List<BloodPressureRecord>?> showImportPreview(
+ BuildContext context,
+ CsvRecordParsingActor initialActor,
+ ExportColumnsManager columnsManager,
+ bool bottomAppBar,) =>
+ showDialog<List<BloodPressureRecord>>(
+ context: context, builder: (context) =>
+ Dialog.fullscreen(
+ child: ImportPreview(
+ bottomAppBar: bottomAppBar,
+ initialActor: initialActor,
+ columnsManager: columnsManager,
+ ),
+ ),
+ );