import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:forui/forui.dart'; import '../../../providers/danmaku_settings_provider.dart'; import '../../../shared/constants/breakpoints.dart'; import '../../../shared/widgets/adaptive_modal.dart'; void showBlockedKeywordsDialog( BuildContext context, WidgetRef ref, List keywords, ) { showAdaptiveModal( context: context, maxWidth: 420, compactMaxHeightFactor: 0.9, builder: (ctx) => _BlockedKeywordsDialog( keywords: keywords, onAdd: (kw) => ref.read(danmakuSettingsProvider.notifier).addBlockedKeyword(kw), onRemove: (kw) => ref.read(danmakuSettingsProvider.notifier).removeBlockedKeyword(kw), ), ); } class _BlockedKeywordsDialog extends StatefulWidget { final List keywords; final ValueChanged onAdd; final ValueChanged onRemove; const _BlockedKeywordsDialog({ required this.keywords, required this.onAdd, required this.onRemove, }); @override State<_BlockedKeywordsDialog> createState() => _BlockedKeywordsDialogState(); } class _BlockedKeywordsDialogState extends State<_BlockedKeywordsDialog> { late final List _keywords; final _controller = TextEditingController(); @override void initState() { super.initState(); _keywords = List.of(widget.keywords); } @override void dispose() { _controller.dispose(); super.dispose(); } void _add() { final text = _controller.text.trim(); if (text.isEmpty || _keywords.contains(text)) return; setState(() => _keywords.add(text)); widget.onAdd(text); _controller.clear(); } void _remove(String kw) { setState(() => _keywords.remove(kw)); widget.onRemove(kw); } @override Widget build(BuildContext context) { final theme = Theme.of(context); final isCompact = Breakpoints.isCompact(MediaQuery.sizeOf(context).width); final chipsMaxHeight = MediaQuery.sizeOf(context).height * (isCompact ? 0.38 : 0.34); return SingleChildScrollView( padding: EdgeInsets.fromLTRB(24, isCompact ? 16 : 24, 24, 24), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text('屏蔽关键词', style: theme.textTheme.titleLarge), const SizedBox(height: 8), Text( '匹配到这些关键词的弹幕将被隐藏', style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), ), const SizedBox(height: 16), Row( children: [ Expanded( child: TextField( controller: _controller, decoration: const InputDecoration( hintText: '输入关键词后回车添加', isDense: true, ), textInputAction: TextInputAction.done, autocorrect: false, enableSuggestions: false, onSubmitted: (_) => _add(), ), ), const SizedBox(width: 8), IconButton.filledTonal( tooltip: '添加', onPressed: _add, icon: const Icon(Icons.add, size: 18), ), ], ), const SizedBox(height: 12), if (_keywords.isEmpty) Padding( padding: const EdgeInsets.symmetric(vertical: 24), child: Text( '暂无屏蔽关键词', textAlign: TextAlign.center, style: TextStyle(color: theme.colorScheme.onSurfaceVariant), ), ) else ConstrainedBox( constraints: BoxConstraints(maxHeight: chipsMaxHeight), child: SingleChildScrollView( child: Wrap( spacing: 8, runSpacing: 8, children: _keywords .map( (kw) => Chip( label: Text(kw), onDeleted: () => _remove(kw), deleteIcon: const Icon(Icons.close, size: 14), ), ) .toList(), ), ), ), const SizedBox(height: 20), if (isCompact) FButton( onPress: () => Navigator.pop(context), child: const Text('完成'), ) else Align( alignment: Alignment.centerRight, child: FButton( variant: FButtonVariant.ghost, onPress: () => Navigator.pop(context), child: const Text('完成'), ), ), ], ), ); } }