smart_form_memory 0.0.4
smart_form_memory: ^0.0.4 copied to clipboard
A smart Flutter form that remembers user input. Features include autosaving, history suggestions, and non-destructive autofill for a seamless user experience.
// Shipping & Delivery Demo for the smart_form_memory package.
//
// This example demonstrates the full lifecycle of the package:
// 1. Automatic Field Registration within a SmartForm.
// 2. Data Persistence (saving form records to local storage).
// 3. Smart History Suggestions (autocomplete based on a unique identifier).
// 4. Non-Destructive Autofill (preserving manual user input).
import 'package:flutter/material.dart';
import 'package:smart_form_memory/smart_form_memory.dart';
void main() {
runApp(const ShippingDeliveryApp());
}
class ShippingDeliveryApp extends StatelessWidget {
const ShippingDeliveryApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Smart Form Pro Demo',
theme: ThemeData(
useMaterial3: true,
colorSchemeSeed: Colors.indigo,
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
),
),
home: const ShippingDeliveryPage(),
);
}
}
class ShippingDeliveryPage extends StatelessWidget {
const ShippingDeliveryPage({super.key});
static const String uniqueKey = 'phone_number';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Smart Shipping Form')),
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: SmartForm(
uniqueFieldKey: uniqueKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const _InstructionsCard(),
const SizedBox(height: 16),
// --- TEXT COMPONENTS ---
_SectionTitle(icon: Icons.person_outline, title: 'Identity'),
const SizedBox(height: 8),
SmartFormTextFormField(
fieldKey: uniqueKey,
keyboardType: TextInputType.phone,
autofillHints: const [AutofillHints.telephoneNumber],
decoration: const InputDecoration(
labelText: 'Phone Number (Unique ID)',
prefixIcon: Icon(Icons.phone_outlined),
helperText:
'Select a previous number to autofill everything below.',
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Phone number is required';
}
return null;
},
),
const SizedBox(height: 12),
const SmartFormTextFormField(
fieldKey: 'full_name',
keyboardType: TextInputType.name,
autofillHints: [AutofillHints.name],
decoration: InputDecoration(
labelText: 'Full Name',
prefixIcon: Icon(Icons.badge_outlined),
),
),
const SizedBox(height: 24),
// --- NEW DROPDOWN COMPONENT ---
_SectionTitle(
icon: Icons.local_shipping_outlined,
title: 'Preferences',
),
const SizedBox(height: 8),
const SmartFormDropdown(
fieldKey: 'delivery_speed',
label: 'Delivery Speed',
items: ['Economy', 'Standard', 'Express', 'Drone Delivery'],
),
const SizedBox(height: 16),
// --- NEW RADIO COMPONENT ---
const SmartFormRadio(
fieldKey: 'address_type',
label: 'Address Type',
options: ['Home', 'Office', 'Friend', 'Other'],
),
const SizedBox(height: 16),
// --- NEW TAG/CHIP COMPONENT ---
const SmartFormTagField(
fieldKey: 'delivery_notes',
label: 'Special Instructions',
tags: [
'Fragile',
'Signature Required',
'Leave at Porch',
'Beware of Dog',
],
),
const SizedBox(height: 24),
// --- ACTION BUTTONS ---
// --- ACTION BUTTONS ---
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(
children: [
// 1. SAVE BUTTON
Expanded(
child: Builder(
builder: (ctx) => FilledButton.icon(
icon: const Icon(Icons.save_outlined),
label: const Text('Save Record'),
onPressed: () async {
final saved =
await SmartForm.of(ctx)?.save() ?? false;
if (saved && ctx.mounted) {
ScaffoldMessenger.of(ctx).showSnackBar(
const SnackBar(
content: Text('Details saved to memory!'),
),
);
}
},
),
),
),
const SizedBox(width: 12),
// 2. CLEAR FIELDS BUTTON (UI ONLY)
Expanded(
child: Builder(
builder: (ctx) => OutlinedButton.icon(
icon: const Icon(Icons.clear_all_rounded),
label: const Text('Clear Form'),
onPressed: () {
SmartForm.of(ctx)?.resetForm();
ScaffoldMessenger.of(ctx).showSnackBar(
const SnackBar(
content: Text('Form inputs cleared.'),
),
);
},
),
),
),
],
),
const SizedBox(height: 12),
// 3. WIPE DATABASE BUTTON (DANGER ZONE)
Builder(
builder: (ctx) => TextButton.icon(
icon: const Icon(
Icons.delete_forever,
color: Colors.red,
),
label: const Text(
'Wipe All Saved History',
style: TextStyle(color: Colors.red),
),
onPressed: () async {
final controller = SmartForm.of(ctx);
// Confirm with user (Optional but good practice)
const storage = SharedPrefsSmartFormStorage();
await storage.clearAll();
// Sync the UI: Refresh ID list and reset the form
await controller?.refreshIds();
controller?.resetForm();
if (ctx.mounted) {
ScaffoldMessenger.of(ctx).showSnackBar(
const SnackBar(
backgroundColor: Colors.red,
content: Text(
'All local history has been deleted.',
),
),
);
}
},
),
),
],
),
],
),
),
),
),
);
}
}
/// A simple helper widget for form sections.
class _SectionTitle extends StatelessWidget {
const _SectionTitle({required this.icon, required this.title});
final IconData icon;
final String title;
@override
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
return Row(
children: [
Icon(icon, color: scheme.primary),
const SizedBox(width: 8),
Text(
title,
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: scheme.primary,
fontWeight: FontWeight.w600,
),
),
],
);
}
}
/// A card that explains the package's non-destructive behavior to the user.
class _InstructionsCard extends StatelessWidget {
const _InstructionsCard();
@override
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
return Card(
elevation: 0,
color: scheme.surfaceContainerHighest.withValues(alpha: 0.3),
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text(
'Testing Non-Destructive Autofill:',
style: TextStyle(fontWeight: FontWeight.bold),
),
SizedBox(height: 4),
Text('• Fields you have already typed in will NOT be overwritten.'),
Text(
'• Only empty fields will be filled when picking a suggestion.',
),
],
),
),
);
}
}