107 lines
3.2 KiB
Dart
107 lines
3.2 KiB
Dart
// Author: fruit.com.cn
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import '../../core/theme/app_colors.dart';
|
|
import '../../core/theme/app_dimens.dart';
|
|
import '../../l10n/app_localizations.dart';
|
|
import 'account_deactivate_logic.dart';
|
|
|
|
/// 注销原因:固定选项在标题下换行排列,补充说明留在输入框内。
|
|
class DeactivateReasonField extends StatelessWidget {
|
|
const DeactivateReasonField({
|
|
super.key,
|
|
required this.controller,
|
|
required this.onChanged,
|
|
});
|
|
|
|
final TextEditingController controller;
|
|
final VoidCallback onChanged;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final l10n = AppLocalizations.of(context)!;
|
|
final options = _options(l10n);
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
l10n.accountDeactivateReason,
|
|
style: const TextStyle(
|
|
color: AppColors.textPrimary,
|
|
fontSize: AppDimens.listTitle,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
const SizedBox(height: AppDimens.spaceSm),
|
|
Wrap(
|
|
spacing: AppDimens.spaceSm,
|
|
runSpacing: AppDimens.spaceSm,
|
|
children: [
|
|
for (var index = 0; index < options.length; index++)
|
|
_chip(options[index], index, options),
|
|
],
|
|
),
|
|
const SizedBox(height: AppDimens.spaceMd),
|
|
TextField(
|
|
key: const Key('account-deactivate-reason'),
|
|
controller: controller,
|
|
maxLength: AccountDeactivateLogic.maxReasonLength,
|
|
minLines: 3,
|
|
maxLines: 4,
|
|
textAlignVertical: TextAlignVertical.top,
|
|
onChanged: (_) => onChanged(),
|
|
decoration: InputDecoration(
|
|
hintText: l10n.accountDeactivateReasonHint,
|
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
|
alignLabelWithHint: true,
|
|
contentPadding: const EdgeInsets.all(AppDimens.cardPadding),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _chip(_ReasonOption option, int index, List<_ReasonOption> options) {
|
|
final selected = option.custom
|
|
? _customSelected(options)
|
|
: controller.text == option.label;
|
|
return ChoiceChip(
|
|
key: Key('account-deactivate-reason-$index'),
|
|
label: Text(option.label),
|
|
selected: selected,
|
|
onSelected: (_) => _select(option),
|
|
);
|
|
}
|
|
|
|
bool _customSelected(List<_ReasonOption> options) {
|
|
final text = controller.text.trim();
|
|
if (text.isEmpty) return false;
|
|
return options
|
|
.where((item) => !item.custom)
|
|
.every((item) => item.label != text);
|
|
}
|
|
|
|
void _select(_ReasonOption option) {
|
|
controller.text = option.custom ? '' : option.label;
|
|
controller.selection = TextSelection.collapsed(
|
|
offset: controller.text.length,
|
|
);
|
|
onChanged();
|
|
}
|
|
|
|
List<_ReasonOption> _options(AppLocalizations l10n) => [
|
|
_ReasonOption(l10n.accountDeactivateReasonUnused),
|
|
_ReasonOption(l10n.accountDeactivateReasonContent),
|
|
_ReasonOption(l10n.accountDeactivateReasonPrivacy),
|
|
_ReasonOption(l10n.accountDeactivateReasonOther, custom: true),
|
|
];
|
|
}
|
|
|
|
class _ReasonOption {
|
|
const _ReasonOption(this.label, {this.custom = false});
|
|
|
|
final String label;
|
|
final bool custom;
|
|
}
|