smart_form_memory 0.0.3
smart_form_memory: ^0.0.3 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),
SmartFormTextField(
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.',
),
),
const SizedBox(height: 12),
const SmartFormTextField(
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) {
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 {
// Confirm with user (Optional but good practice)
const storage = SharedPrefsSmartFormStorage();
await storage.clearAll();
// Sync the UI: Refresh ID list and reset the form
final controller = SmartForm.of(ctx);
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) {
return Card(
elevation: 0,
color: Theme.of(context).colorScheme.surfaceVariant.withOpacity(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.'),
],
),
),
);
}
}