import 'package:flutter/material.dart'; import 'package:forui/forui.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../core/contracts/danmaku.dart'; import '../../../providers/danmaku_settings_provider.dart'; import '../../../shared/widgets/setting_select.dart'; import '../utils/settings_labels.dart'; import '../widgets/blocked_keywords_dialog.dart'; import '../widgets/danmaku_sources_dialog.dart'; import '../widgets/settings_card.dart'; import '../widgets/settings_stepper_row.dart'; class DanmakuSettingsTab extends ConsumerWidget { const DanmakuSettingsTab({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final danmakuSettings = ref.watch(danmakuSettingsProvider); return SettingsTabScroll( children: [ danmakuSettings.when( data: (data) => Column( children: [ SettingsCard( children: [ SettingRow( title: '全局启用弹幕', trailing: FSwitch( value: data.enabled, onChange: (v) => ref .read(danmakuSettingsProvider.notifier) .setEnabled(v), ), ), ], ), if (data.enabled) ...[ _buildDanmakuDisplayCard(context, ref, data.panelSettings), SettingsCard( children: [ SettingRow( title: '简繁转换', subtitle: '仅对兼容原版 dandanplay 的源生效', trailing: SettingSelect( value: data.chineseConvert, options: ChineseConvertMode.values, labelOf: chineseConvertLabel, onChanged: (v) { if (v != null) { ref .read(danmakuSettingsProvider.notifier) .setChineseConvert(v); } }, ), ), SettingRow( title: '弹幕源', subtitle: danmakuSourcesSummary(data.sources), trailing: const Icon(Icons.chevron_right, size: 18), onTap: () => showDanmakuSourcesDialog(context, data.sources), ), SettingRow( title: '合并重复弹幕', trailing: FSwitch( value: data.mergeDuplicates, onChange: (v) => ref .read(danmakuSettingsProvider.notifier) .setMergeDuplicates(v), ), ), SettingRow( title: '屏蔽关键词', subtitle: data.blockedKeywords.isEmpty ? '未设置' : '${data.blockedKeywords.length} 个', trailing: const Icon(Icons.chevron_right, size: 18), onTap: () => showBlockedKeywordsDialog( context, ref, data.blockedKeywords, ), ), ], ), ], ], ), loading: () => const SizedBox.shrink(), error: (e, _) => settingsLoadError(e), ), ], ); } Widget _buildDanmakuDisplayCard( BuildContext context, WidgetRef ref, DanmakuPanelSettings p, ) { void emit(DanmakuPanelSettings next) => ref.read(danmakuSettingsProvider.notifier).updatePanelSettings(next); double inc(double v, double step, double min, double max) => double.parse((v + step).clamp(min, max).toStringAsFixed(2)); double dec(double v, double step, double min, double max) => double.parse((v - step).clamp(min, max).toStringAsFixed(2)); String opacityStr(double v) => (v * 10).round() == 10 ? '1.0' : '0.${(v * 10).round()}'; return Column( children: [ SettingsCard( children: [ StepperRow( title: '字号大小', display: p.fontSize.round().toString(), onDecrement: p.fontSize > 12 ? () => emit(p.copyWith(fontSize: dec(p.fontSize, 2, 12, 40))) : null, onIncrement: p.fontSize < 40 ? () => emit(p.copyWith(fontSize: inc(p.fontSize, 2, 12, 40))) : null, ), StepperRow( title: '基础速度', display: '${p.speed.toStringAsFixed(2)}x', onDecrement: p.speed > 0.25 ? () => emit(p.copyWith(speed: dec(p.speed, 0.25, 0.25, 2.0))) : null, onIncrement: p.speed < 2.0 ? () => emit(p.copyWith(speed: inc(p.speed, 0.25, 0.25, 2.0))) : null, ), StepperRow( title: '不透明度', display: opacityStr(p.opacity), onDecrement: p.opacity > 0.1 ? () => emit(p.copyWith(opacity: dec(p.opacity, 0.1, 0.1, 1.0))) : null, onIncrement: p.opacity < 1.0 ? () => emit(p.copyWith(opacity: inc(p.opacity, 0.1, 0.1, 1.0))) : null, ), StepperRow( title: '描边大小', display: p.strokeWidth.toStringAsFixed(1), onDecrement: p.strokeWidth > 0.0 ? () => emit( p.copyWith( strokeWidth: dec(p.strokeWidth, 0.5, 0.0, 3.0), ), ) : null, onIncrement: p.strokeWidth < 3.0 ? () => emit( p.copyWith( strokeWidth: inc(p.strokeWidth, 0.5, 0.0, 3.0), ), ) : null, ), StepperRow( title: '行间距', display: p.lineHeight.toStringAsFixed(1), onDecrement: p.lineHeight > 1.0 ? () => emit( p.copyWith(lineHeight: dec(p.lineHeight, 0.1, 1.0, 3.0)), ) : null, onIncrement: p.lineHeight < 3.0 ? () => emit( p.copyWith(lineHeight: inc(p.lineHeight, 0.1, 1.0, 3.0)), ) : null, ), StepperRow( title: '弹幕行数', display: p.maxRows == 0 ? '自动' : '${p.maxRows} 行', onDecrement: p.maxRows > 0 ? () => emit(p.copyWith(maxRows: p.maxRows - 1)) : null, onIncrement: p.maxRows < 10 ? () => emit(p.copyWith(maxRows: p.maxRows + 1)) : null, ), ], ), SettingsCard( children: [ SettingRow( title: '粗体', trailing: FSwitch( value: p.bold, onChange: (v) => emit(p.copyWith(bold: v)), ), ), SettingRow( title: '固定弹幕转滚动', trailing: FSwitch( value: p.fixedToScroll, onChange: (v) => emit(p.copyWith(fixedToScroll: v)), ), ), ], ), ], ); } }