Files
monisuo/flutter_monisuo/lib/ui/components/glass_panel.dart
sion123 7ed2435a4c refactor(theme): 迁移主题感知颜色至 ThemeExtension
- 创建 AppThemeColors ThemeExtension 类,统一管理主题感知颜色(涨跌色、卡片背景、渐变等)
- 从 AppColorScheme 移除主题感知辅助函数,仅保留静态颜色常量
- 在 AppTheme 中注册 ThemeExtension,支持深色/浅色主题工厂
- 重构所有 UI 组件使用 context.appColors 访问主题颜色,替代硬编码的 AppColorScheme 方法调用
- 移除组件中重复的 isDark 判断逻辑,简化颜色获取方式
- 保持向后兼容性,所有现有功能不变
2026-04-06 01:58:08 +08:00

298 lines
7.1 KiB
Dart

import 'package:flutter/material.dart';
import '../../core/theme/app_spacing.dart';
import '../../core/theme/app_theme_extension.dart';
/// GlassPanel - 实心背景面板
///
/// Material Design 3 风格的实心背景容器
/// 用于卡片、弹窗、底部抽屉等需要清晰背景的容器
///
/// 示例:
/// ```dart
/// GlassPanel(
/// child: Text('内容'),
/// )
/// ```
class GlassPanel extends StatelessWidget {
/// 子组件
final Widget child;
/// 背景色,默认使用 surfaceContainer
final Color? backgroundColor;
/// 边框色
final Color? borderColor;
/// 圆角,默认特大圆角
final BorderRadius? borderRadius;
/// 内边距
final EdgeInsetsGeometry? padding;
/// 外边距
final EdgeInsetsGeometry? margin;
/// 宽度
final double? width;
/// 高度
final double? height;
/// 是否显示边框
final bool showBorder;
const GlassPanel({
super.key,
required this.child,
this.backgroundColor,
this.borderColor,
this.borderRadius,
this.padding,
this.margin,
this.width,
this.height,
this.showBorder = true,
});
@override
Widget build(BuildContext context) {
final bgColor = backgroundColor ?? context.appColors.surfaceCard;
final brColor = borderColor ?? context.appColors.ghostBorder;
final br = borderRadius ?? BorderRadius.circular(AppRadius.xl);
Widget content = Container(
width: width,
height: height,
padding: padding ?? EdgeInsets.all(AppSpacing.md),
decoration: BoxDecoration(
color: bgColor,
borderRadius: br,
border: showBorder
? Border.all(
color: brColor,
width: 1,
)
: null,
),
child: child,
);
if (margin != null) {
content = Padding(
padding: margin!,
child: content,
);
}
return content;
}
}
/// GlassCard - 带实心背景的卡片
///
/// 用于列表项、信息展示等场景
/// 预设了常用配置,简化使用
class GlassCard extends StatelessWidget {
/// 子组件
final Widget child;
/// 点击回调
final VoidCallback? onTap;
/// 长按回调
final VoidCallback? onLongPress;
/// 内边距
final EdgeInsetsGeometry? padding;
/// 外边距
final EdgeInsetsGeometry? margin;
/// 圆角
final BorderRadius? borderRadius;
/// 是否显示霓虹光效
final bool showNeonGlow;
/// 霓虹光效颜色
final Color? neonGlowColor;
const GlassCard({
super.key,
required this.child,
this.onTap,
this.onLongPress,
this.padding,
this.margin,
this.borderRadius,
this.showNeonGlow = false,
this.neonGlowColor,
});
@override
Widget build(BuildContext context) {
final br = borderRadius ?? BorderRadius.circular(AppRadius.xl);
final glowColor = neonGlowColor ??
context.colors.primary.withValues(alpha: context.appColors.glowOpacity);
Widget card = GlassPanel(
padding: padding ?? EdgeInsets.all(AppSpacing.md),
margin: margin,
borderRadius: br,
child: child,
);
if (showNeonGlow) {
card = Container(
decoration: BoxDecoration(
borderRadius: br,
boxShadow: [
BoxShadow(
color: glowColor,
blurRadius: 15,
spreadRadius: 0,
),
],
),
child: card,
);
}
if (onTap != null || onLongPress != null) {
return GestureDetector(
onTap: onTap,
onLongPress: onLongPress,
child: card,
);
}
return card;
}
}
/// GlassBottomSheet - 实心背景底部抽屉
///
/// 用于弹出的底部面板
class GlassBottomSheet extends StatelessWidget {
/// 子组件
final Widget child;
/// 标题
final String? title;
/// 是否显示关闭按钮
final bool showCloseButton;
/// 内边距
final EdgeInsetsGeometry? padding;
const GlassBottomSheet({
super.key,
required this.child,
this.title,
this.showCloseButton = true,
this.padding,
});
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: context.appColors.surfaceCard,
borderRadius: const BorderRadius.vertical(
top: Radius.circular(AppRadius.xxl),
),
border: Border.all(
color: context.appColors.ghostBorder,
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// 顶部拖动条
Container(
margin: const EdgeInsets.only(top: 12, bottom: 8),
width: 40,
height: 4,
decoration: BoxDecoration(
color: context.colors.outlineVariant.withValues(alpha: 0.5),
borderRadius: BorderRadius.circular(2),
),
),
// 标题栏
if (title != null || showCloseButton)
Padding(
padding: EdgeInsets.fromLTRB(
AppSpacing.lg,
AppSpacing.sm,
AppSpacing.sm,
AppSpacing.md,
),
child: Row(
children: [
if (title != null)
Expanded(
child: Text(
title!,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: context.colors.onSurface,
),
),
),
if (showCloseButton)
GestureDetector(
onTap: () => Navigator.of(context).pop(),
child: Container(
padding: EdgeInsets.all(AppSpacing.sm),
decoration: BoxDecoration(
color: context.colors.outlineVariant
.withOpacity(0.2),
shape: BoxShape.circle,
),
child: Icon(
Icons.close,
size: 18,
color: context.colors.onSurfaceVariant,
),
),
),
],
),
),
// 内容
Padding(
padding: padding ??
EdgeInsets.fromLTRB(
AppSpacing.lg,
0,
AppSpacing.lg,
AppSpacing.xl,
),
child: child,
),
],
),
);
}
/// 显示底部抽屉
static Future<T?> show<T>({
required BuildContext context,
required Widget Function(BuildContext) builder,
bool isScrollControlled = false,
bool isDismissible = true,
bool enableDrag = true,
}) {
return showModalBottomSheet<T>(
context: context,
isScrollControlled: isScrollControlled,
isDismissible: isDismissible,
enableDrag: enableDrag,
backgroundColor: Colors.transparent,
builder: builder,
);
}
}