/// Name prompt that owns its text controller for the dialog lifetime. library; import 'package:flutter/material.dart'; Future showNameDialog( BuildContext context, { required String title, String? initial, String label = 'Name', String confirmLabel = 'Save', }) { return showDialog( context: context, builder: (context) => _NameDialog( title: title, initial: initial ?? '', label: label, confirmLabel: confirmLabel, ), ); } class _NameDialog extends StatefulWidget { const _NameDialog({ required this.title, required this.initial, required this.label, required this.confirmLabel, }); final String title; final String initial; final String label; final String confirmLabel; @override State<_NameDialog> createState() => _NameDialogState(); } class _NameDialogState extends State<_NameDialog> { late final TextEditingController _controller; String? _error; @override void initState() { super.initState(); _controller = TextEditingController(text: widget.initial); } @override void dispose() { _controller.dispose(); super.dispose(); } void _save() { final name = _controller.text.trim(); if (name.isEmpty) { setState(() => _error = 'Enter a name.'); return; } Navigator.of(context).pop(name); } @override Widget build(BuildContext context) { return AlertDialog( title: Text(widget.title), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: _controller, autofocus: true, textCapitalization: TextCapitalization.sentences, decoration: InputDecoration(labelText: widget.label), onSubmitted: (_) => _save(), ), if (_error != null) ...[ const SizedBox(height: 8), Align( alignment: Alignment.centerLeft, child: Text( _error!, style: TextStyle(color: Theme.of(context).colorScheme.error), ), ), ], ], ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('Cancel'), ), TextButton(onPressed: _save, child: Text(widget.confirmLabel)), ], ); } }