mobile_nebula/lib/components/FormPage.dart
Ian VanSchooten 64d45f66c7
Update Flutter, target android SDK 34 (#160)
This updates flutter to 3.24.1, the latest stable version, and also updates our flutter dependencies to latest.

It targets the latest android sdk, 34, which is required if we want to publish a new version to the Google Play store.

I also needed to make a few adjustments to handle deprecations. The biggest change is that I needed to wrap the main widget in MaterialApp to avoid problems with AdaptiveSwitch in iOS.
2024-09-20 14:19:23 -04:00

103 lines
2.8 KiB
Dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/widgets.dart';
import 'package:mobile_nebula/components/SimplePage.dart';
import 'package:mobile_nebula/services/utils.dart';
/// SimplePage with a form and built in validation and confirmation to discard changes if any are made
class FormPage extends StatefulWidget {
const FormPage(
{Key? key,
required this.title,
required this.child,
required this.onSave,
required this.changed,
this.hideSave = false,
this.scrollController})
: super(key: key);
final String title;
final Function onSave;
final Widget child;
final ScrollController? scrollController;
/// If you need the page to progress to a certain point before saving, control it here
final bool hideSave;
/// Useful if you have a non form field that can change, overrides the internal changed state if true
final bool changed;
@override
_FormPageState createState() => _FormPageState();
}
class _FormPageState extends State<FormPage> {
var changed = false;
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
changed = widget.changed || changed;
return PopScope<Object?>(
canPop: false,
onPopInvokedWithResult: (bool didPop, Object? result) async {
if (didPop) {
return;
}
final NavigatorState navigator = Navigator.of(context);
Utils.confirmDelete(context, 'Discard changes?', () {
navigator.pop();
}, deleteLabel: 'Yes', cancelLabel: 'No');
},
child: SimplePage(
leadingAction: _buildLeader(context),
trailingActions: _buildTrailer(context),
scrollController: widget.scrollController,
title: Text(widget.title),
child: Form(
key: _formKey,
onChanged: () => setState(() {
changed = true;
}),
child: widget.child),
));
}
Widget _buildLeader(BuildContext context) {
return Utils.leadingBackWidget(context, label: changed ? 'Cancel' : 'Back', onPressed: () {
if (changed) {
Utils.confirmDelete(context, 'Discard changes?', () {
changed = false;
Navigator.pop(context);
}, deleteLabel: 'Yes', cancelLabel: 'No');
} else {
Navigator.pop(context);
}
});
}
List<Widget> _buildTrailer(BuildContext context) {
if (!changed || widget.hideSave) {
return [];
}
return [
Utils.trailingSaveWidget(
context,
() {
if (_formKey.currentState == null) {
return;
}
if (!_formKey.currentState!.validate()) {
return;
}
_formKey.currentState!.save();
widget.onSave();
},
)
];
}
}