Files
kuaishai2/lib/features/settings/widgets/password_panel.dart
Developer 3d849bd468 feat(i18n): 完成全量 UI 文本国际化,替换所有硬编码中文为 AppLocalizations 调用
- core/localization: 新增约 60 个翻译键(含参数化方法),中英双语覆盖
- shared/widgets: CommonDialog 默认参数国际化
- features/home: 完成页操作步骤指引、状态栏串口连接状态、程序列表状态标签
- features/programs: 表头状态列、表单验证提示、导入/模板操作反馈、删除确认(参数化)
- features/program_detail: 步骤列表/表单标题、删除确认、速度档位显示(参数化)
- features/device: run_state_provider 错误消息改为错误码
- features/settings: 升级页、密码面板、语言面板、U盘导入面板、串口配置面板全部替换

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-12 15:09:47 +08:00

199 lines
6.3 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../core/localization/app_localizations.dart';
import '../../../core/theme/app_theme.dart';
import '../../../shared/services/toast_service.dart';
import '../services/settings_service.dart';
/// 密码修改面板
///
/// 在设置页右侧主区域渲染密码修改表单,行为与原弹窗一致:
/// 校验空值、长度≥6、两次一致性、原密码正确性。
class PasswordPanel extends ConsumerStatefulWidget {
const PasswordPanel({super.key});
@override
ConsumerState<PasswordPanel> createState() => _PasswordPanelState();
}
class _PasswordPanelState extends ConsumerState<PasswordPanel> {
final _oldCtrl = TextEditingController();
final _newCtrl = TextEditingController();
final _confirmCtrl = TextEditingController();
bool _submitting = false;
String? _error;
@override
void dispose() {
_oldCtrl.dispose();
_newCtrl.dispose();
_confirmCtrl.dispose();
super.dispose();
}
Future<void> _submit() async {
if (_submitting) return;
final l10n = AppLocalizations.of(context);
final oldPwd = _oldCtrl.text.trim();
final newPwd = _newCtrl.text.trim();
final confirmPwd = _confirmCtrl.text.trim();
if (oldPwd.isEmpty || newPwd.isEmpty || confirmPwd.isEmpty) {
setState(() => _error = l10n?.fillAllFields ?? '请填写所有字段');
return;
}
if (newPwd.length < 6) {
setState(() => _error = l10n?.newPwdMinLength ?? '新密码至少6位字符');
return;
}
if (newPwd != confirmPwd) {
setState(() => _error = l10n?.passwordMismatch ?? '两次输入的新密码不一致');
return;
}
setState(() {
_submitting = true;
_error = null;
});
final isValid = await SettingsService.instance.verifyPassword(oldPwd);
if (!isValid) {
if (!mounted) return;
setState(() {
_submitting = false;
_error = l10n?.oldPasswordError ?? '原密码错误';
});
return;
}
final ok = await SettingsService.instance.setPassword(newPwd);
if (!mounted) return;
setState(() => _submitting = false);
if (ok) {
_oldCtrl.clear();
_newCtrl.clear();
_confirmCtrl.clear();
ToastService.showSuccess(context, l10n?.passwordChanged ?? '密码已修改');
} else {
ToastService.showError(context, l10n?.passwordChangeFailed ?? '密码修改失败');
}
}
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context);
return ListView(
padding: EdgeInsets.zero,
children: [
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppTheme.borderSubtle),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
l10n?.password ?? '密码修改',
style: TextStyle(
color: AppTheme.textPrimary,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
const Divider(),
_field(
controller: _oldCtrl,
label: l10n?.oldPassword ?? '原密码',
hint: l10n?.enterCurrentPassword ?? '请输入当前密码',
),
const SizedBox(height: 16),
_field(
controller: _newCtrl,
label: l10n?.newPassword ?? '新密码',
hint: l10n?.passwordMinLength ?? '至少6位字符',
),
const SizedBox(height: 16),
_field(
controller: _confirmCtrl,
label: l10n?.confirmNewPassword ?? '确认新密码',
hint: l10n?.enterNewPassword ?? '再次输入新密码',
),
if (_error != null) ...[
const SizedBox(height: 12),
Text(
_error!,
style: TextStyle(color: AppTheme.errorColor, fontSize: 12),
),
],
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
OutlinedButton(
onPressed: _submitting
? null
: () {
_oldCtrl.clear();
_newCtrl.clear();
_confirmCtrl.clear();
setState(() => _error = null);
},
child: Text(l10n?.reset ?? '重置'),
),
const SizedBox(width: 12),
ElevatedButton.icon(
onPressed: _submitting ? null : _submit,
icon: _submitting
? const SizedBox(
width: 14,
height: 14,
child: CircularProgressIndicator(
strokeWidth: 2,
color: Colors.white,
),
)
: const Icon(Icons.check, size: 18),
label: Text(l10n?.confirm ?? '确认'),
),
],
),
],
),
),
const SizedBox(height: 16),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: Text(
l10n?.defaultPassword ?? '默认密码为 123456',
style: TextStyle(color: AppTheme.textSecondary, fontSize: 12),
),
),
],
);
}
Widget _field({
required TextEditingController controller,
required String label,
required String hint,
}) {
return TextField(
controller: controller,
obscureText: true,
decoration: InputDecoration(
labelText: label,
hintText: hint,
border: const OutlineInputBorder(),
isDense: true,
contentPadding:
const EdgeInsets.symmetric(horizontal: 12, vertical: 12),
),
);
}
}