import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../core/models/models.dart'; import '../../../core/network/api_exception.dart'; import '../../../data/repositories/node_repository.dart'; /// Edit dialog for the node-level [BackupConfig]'s source path. Target /// management (add/edit/remove/run/schedule) lives in the dedicated /// [BackupTargetsList] on the Backups screen, not in this dialog. Future showBackupConfigFormDialog(BuildContext context, {required BackupConfig existing}) { return showDialog( context: context, builder: (context) => _BackupConfigFormDialog(existing: existing), ); } class _BackupConfigFormDialog extends ConsumerStatefulWidget { const _BackupConfigFormDialog({required this.existing}); final BackupConfig existing; @override ConsumerState<_BackupConfigFormDialog> createState() => _BackupConfigFormDialogState(); } class _BackupConfigFormDialogState extends ConsumerState<_BackupConfigFormDialog> { late final _sourcePathController = TextEditingController(text: widget.existing.sourcePath); bool _saving = false; String? _error; @override void dispose() { _sourcePathController.dispose(); super.dispose(); } Future _save() async { setState(() { _saving = true; _error = null; }); final repo = ref.read(nodeRepositoryProvider); if (repo == null) { setState(() { _saving = false; _error = 'No active connection.'; }); return; } final draft = widget.existing.copyWith(sourcePath: _sourcePathController.text.trim()); try { await repo.updateBackup(draft); ref.invalidate(backupConfigProvider); if (mounted) Navigator.of(context).pop(); } catch (e) { setState(() { _saving = false; _error = e is ApiException ? e.userMessage : e.toString(); }); } } @override Widget build(BuildContext context) { return AlertDialog( title: const Text('Edit backup configuration'), content: SizedBox( width: 420, child: Column( mainAxisSize: MainAxisSize.min, children: [ TextFormField( controller: _sourcePathController, decoration: const InputDecoration(labelText: 'Source path', hintText: '/opt'), ), if (_error != null) ...[ const SizedBox(height: 12), Text(_error!, style: TextStyle(color: Theme.of(context).colorScheme.error)), ], ], ), ), actions: [ TextButton( onPressed: _saving ? null : () => Navigator.of(context).pop(), child: const Text('Cancel'), ), FilledButton( onPressed: _saving ? null : _save, child: _saving ? const SizedBox(width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2)) : const Text('Save'), ), ], ); } }