import 'package:flutter/material.dart'; import '../models/theme_group.dart'; /// 门店界面配置:按设备分组展示已添加的主题。 /// /// 每组横向滚动显示主题卡片,激活主题带高亮边框; /// 点击主题卡片触发 [onThemeTap]。 class StoreThemeGroupList extends StatelessWidget { const StoreThemeGroupList({ super.key, required this.groups, this.onThemeTap, this.emptyHint, }); /// 分组及主题数据。 final List groups; /// 主题点击回调;参数为 (groupId, theme)。 final void Function(int groupId, ThemePage theme)? onThemeTap; /// 空数据提示文案。 final String? emptyHint; @override Widget build(BuildContext context) { if (groups.isEmpty) { return SizedBox( height: 80, child: Center( child: Text( emptyHint ?? '暂无界面配置数据', style: TextStyle( color: Theme.of(context).colorScheme.onSurfaceVariant, ), ), ), ); } return Column( crossAxisAlignment: CrossAxisAlignment.start, children: groups.map((group) => _buildGroup(context, group)).toList(), ); } Widget _buildGroup(BuildContext context, ThemeGroup group) { final theme = Theme.of(context); return Padding( padding: const EdgeInsets.only(bottom: 16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( group.groupName, style: theme.textTheme.titleSmall ?.copyWith(fontWeight: FontWeight.bold), ), ), Text( '${group.themes.length}/${group.themeLimit}', style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), ), ], ), if (group.activeThemeName != null) Padding( padding: const EdgeInsets.only(top: 2, bottom: 6), child: Text( '当前:${group.activeThemeName}', style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.primary, ), ), ) else const SizedBox(height: 6), SizedBox( height: 132, child: ListView.separated( scrollDirection: Axis.horizontal, itemCount: group.themes.length, separatorBuilder: (_, __) => const SizedBox(width: 10), itemBuilder: (context, index) { final themePage = group.themes[index]; return _ThemeCard( themePage: themePage, onTap: onThemeTap != null ? () => onThemeTap!(group.groupId, themePage) : null, ); }, ), ), ], ), ); } } class _ThemeCard extends StatelessWidget { const _ThemeCard({ required this.themePage, this.onTap, }); final ThemePage themePage; final VoidCallback? onTap; @override Widget build(BuildContext context) { final primary = Theme.of(context).colorScheme.primary; final photoUrl = themePage.themePhoto; return InkWell( onTap: onTap, borderRadius: BorderRadius.circular(10), child: Container( width: 120, decoration: BoxDecoration( color: Theme.of(context).colorScheme.surfaceContainerHighest, borderRadius: BorderRadius.circular(10), border: Border.all( color: themePage.active ? primary : Colors.transparent, width: themePage.active ? 2 : 1, ), ), child: Column( children: [ Expanded( child: ClipRRect( borderRadius: const BorderRadius.vertical(top: Radius.circular(9)), child: Container( width: double.infinity, color: photoUrl == null || photoUrl.isEmpty ? primary.withOpacity(0.2) : null, child: photoUrl != null && photoUrl.isNotEmpty ? Image.network( photoUrl, fit: BoxFit.cover, errorBuilder: (_, __, ___) => _placeholder(primary), ) : _placeholder(primary), ), ), ), Container( height: 34, alignment: Alignment.center, padding: const EdgeInsets.symmetric(horizontal: 6), child: Text( themePage.name.isEmpty ? '未命名主题' : themePage.name, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(fontSize: 12), ), ), ], ), ), ); } Widget _placeholder(Color primary) { return Center( child: Icon(Icons.image_outlined, color: primary, size: 28), ); } }