import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:forui/forui.dart'; import '../../core/domain/errors.dart'; import '../../providers/di_providers.dart'; import '../constants/breakpoints.dart'; import '../utils/user_error_formatter.dart'; import 'adaptive_modal.dart'; import 'app_inline_alert.dart'; import 'app_loading_ring.dart'; import 'app_snack_bar.dart'; Future showServerChangePasswordDialog({ required BuildContext context, required String serverId, required String serverName, }) => showAdaptiveModal( context: context, maxWidth: 420, compactMaxHeightFactor: 0.9, builder: (_) => _ServerChangePasswordDialog(serverId: serverId, serverName: serverName), ); class _ServerChangePasswordDialog extends ConsumerStatefulWidget { final String serverId; final String serverName; const _ServerChangePasswordDialog({ required this.serverId, required this.serverName, }); @override ConsumerState<_ServerChangePasswordDialog> createState() => _ServerChangePasswordDialogState(); } class _ServerChangePasswordDialogState extends ConsumerState<_ServerChangePasswordDialog> { final _currentPwCtrl = TextEditingController(); final _newPwCtrl = TextEditingController(); final _confirmPwCtrl = TextEditingController(); bool _loading = false; String? _error; @override void dispose() { _currentPwCtrl.dispose(); _newPwCtrl.dispose(); _confirmPwCtrl.dispose(); super.dispose(); } Future _submit() async { final currentPw = _currentPwCtrl.text; final newPw = _newPwCtrl.text; final confirmPw = _confirmPwCtrl.text; if (currentPw.isEmpty || newPw.isEmpty || confirmPw.isEmpty) { setState(() => _error = '所有字段不能为空'); return; } if (newPw != confirmPw) { setState(() => _error = '两次输入的新密码不一致'); return; } setState(() { _loading = true; _error = null; }); try { final uc = await ref.read(changePasswordUseCaseProvider.future); await uc.execute( serverId: widget.serverId, currentPassword: currentPw, newPassword: newPw, ); if (mounted) Navigator.of(context).pop(); if (mounted) { showAppSnackBar(context, '密码已修改', tone: AppSnackTone.neutral); } } catch (e) { if (!mounted) return; setState(() { _loading = false; _error = e is DomainError ? formatUserError(e) : '修改失败,请检查当前密码是否正确'; }); } } @override Widget build(BuildContext context) { final isCompact = Breakpoints.isCompact(MediaQuery.sizeOf(context).width); final title = Text('修改密码 · ${widget.serverName}'); final body = SingleChildScrollView( padding: EdgeInsets.fromLTRB(24, isCompact ? 16 : 24, 24, 24), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ title, const SizedBox(height: 18), TextField( controller: _currentPwCtrl, obscureText: true, enabled: !_loading, textInputAction: TextInputAction.next, autocorrect: false, enableSuggestions: false, decoration: const InputDecoration(labelText: '当前密码'), ), const SizedBox(height: 12), TextField( controller: _newPwCtrl, obscureText: true, enabled: !_loading, textInputAction: TextInputAction.next, autocorrect: false, enableSuggestions: false, decoration: const InputDecoration(labelText: '新密码'), ), const SizedBox(height: 12), TextField( controller: _confirmPwCtrl, obscureText: true, enabled: !_loading, textInputAction: TextInputAction.done, autocorrect: false, enableSuggestions: false, onSubmitted: (_) => _submit(), decoration: const InputDecoration(labelText: '确认新密码'), ), if (_error != null) ...[ const SizedBox(height: 12), AppInlineAlert(message: _error!), ], const SizedBox(height: 20), if (isCompact) FButton( onPress: _loading ? null : _submit, child: _loading ? const AppLoadingRing(size: 16, color: Colors.white) : const Text('确认修改'), ) else Row( mainAxisAlignment: MainAxisAlignment.end, children: [ FButton( variant: FButtonVariant.ghost, onPress: _loading ? null : () => Navigator.of(context).pop(), child: const Text('取消'), ), const SizedBox(width: 8), FButton( onPress: _loading ? null : _submit, child: _loading ? const AppLoadingRing(size: 16, color: Colors.white) : const Text('确认修改'), ), ], ), if (isCompact) ...[ const SizedBox(height: 8), FButton( variant: FButtonVariant.outline, onPress: _loading ? null : () => Navigator.of(context).pop(), child: const Text('取消'), ), ], ], ), ); return PopScope(canPop: !_loading, child: body); } }