From f789bb7eff0c3772da5d512e22460c3f5134dac5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 19:20:50 +0000 Subject: [PATCH] Add input validation for collection names (min 2, max 50 chars) Co-authored-by: derkauzigekoala <79001016+derkauzigekoala@users.noreply.github.com> --- lib/screens/collections_screen.dart | 53 ++++++++++++++--------- lib/screens/manage_collection_screen.dart | 47 ++++++++++++-------- 2 files changed, 63 insertions(+), 37 deletions(-) diff --git a/lib/screens/collections_screen.dart b/lib/screens/collections_screen.dart index ef24d59..f64b8b7 100644 --- a/lib/screens/collections_screen.dart +++ b/lib/screens/collections_screen.dart @@ -50,6 +50,7 @@ class CollectionsScreenState extends State { } Future _createCollection() async { + final formKey = GlobalKey(); final nameCtrl = TextEditingController(); final descCtrl = TextEditingController(); @@ -65,26 +66,37 @@ class CollectionsScreenState extends State { child: const Icon(Icons.add, color: Colors.white, size: 28), ), title: const Text('New Collection'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - TextField( - controller: nameCtrl, - autofocus: true, - decoration: const InputDecoration( - labelText: 'Name', - hintText: 'e.g. Hot Wheels, Matchbox…', + content: Form( + key: formKey, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextFormField( + controller: nameCtrl, + autofocus: true, + maxLength: 50, + decoration: const InputDecoration( + labelText: 'Name', + hintText: 'e.g. Hot Wheels, Matchbox…', + ), + validator: (value) { + final trimmed = value?.trim() ?? ''; + if (trimmed.isEmpty) return 'Name is required'; + if (trimmed.length < 2) return 'Name must be at least 2 characters'; + if (trimmed.length > 50) return 'Name must be 50 characters or fewer'; + return null; + }, ), - ), - const SizedBox(height: 12), - TextField( - controller: descCtrl, - decoration: const InputDecoration( - labelText: 'Description (optional)', - hintText: 'What is this collection for?', + const SizedBox(height: 12), + TextField( + controller: descCtrl, + decoration: const InputDecoration( + labelText: 'Description (optional)', + hintText: 'What is this collection for?', + ), ), - ), - ], + ], + ), ), actions: [ TextButton( @@ -93,8 +105,9 @@ class CollectionsScreenState extends State { ), ElevatedButton( onPressed: () { - if (nameCtrl.text.trim().isEmpty) return; - Navigator.pop(context, true); + if (formKey.currentState!.validate()) { + Navigator.pop(context, true); + } }, child: const Text('Create'), ), diff --git a/lib/screens/manage_collection_screen.dart b/lib/screens/manage_collection_screen.dart index faa93b1..1614e54 100644 --- a/lib/screens/manage_collection_screen.dart +++ b/lib/screens/manage_collection_screen.dart @@ -44,6 +44,7 @@ class _ManageCollectionScreenState extends State { } Future _rename() async { + final formKey = GlobalKey(); final ctrl = TextEditingController(text: _collection.name); final descCtrl = TextEditingController(text: _collection.description ?? ''); @@ -52,21 +53,32 @@ class _ManageCollectionScreenState extends State { context: context, builder: (_) => AlertDialog( title: const Text('Rename Collection'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - TextField( - controller: ctrl, - autofocus: true, - decoration: const InputDecoration(labelText: 'Name'), - ), - const SizedBox(height: 12), - TextField( - controller: descCtrl, - decoration: - const InputDecoration(labelText: 'Description (optional)'), - ), - ], + content: Form( + key: formKey, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextFormField( + controller: ctrl, + autofocus: true, + maxLength: 50, + decoration: const InputDecoration(labelText: 'Name'), + validator: (value) { + final trimmed = value?.trim() ?? ''; + if (trimmed.isEmpty) return 'Name is required'; + if (trimmed.length < 2) return 'Name must be at least 2 characters'; + if (trimmed.length > 50) return 'Name must be 50 characters or fewer'; + return null; + }, + ), + const SizedBox(height: 12), + TextField( + controller: descCtrl, + decoration: + const InputDecoration(labelText: 'Description (optional)'), + ), + ], + ), ), actions: [ TextButton( @@ -75,8 +87,9 @@ class _ManageCollectionScreenState extends State { ), ElevatedButton( onPressed: () { - if (ctrl.text.trim().isEmpty) return; - Navigator.pop(context, true); + if (formKey.currentState!.validate()) { + Navigator.pop(context, true); + } }, child: const Text('Save'), ),