// Author: fruit.com.cn import 'package:flutter/material.dart'; import '../../../core/theme/app_colors.dart'; import '../../../core/theme/app_dimens.dart'; import '../../../core/widgets/app_press_scale.dart'; import '../../../l10n/app_localizations.dart'; import '../mine_types.dart'; const int _gridColumnCount = 4; const double _gridMaxTextScale = 1.2; /// 「我的」页统一操作宫格:常用入口与服务入口按 4×2 排列。 class MineActionGrid extends StatelessWidget { const MineActionGrid({ super.key, required this.primaryActions, required this.serviceActions, }); final MinePrimaryActions primaryActions; final MineServiceActions serviceActions; @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; final items = [..._primaryItems(l10n), ..._serviceItems(l10n)]; return SizedBox( height: AppDimens.mineGridHeight, child: DecoratedBox( key: const Key('mine-menu'), decoration: BoxDecoration( color: AppColors.mineGridSurface, border: Border.all(color: AppColors.glassHairline), borderRadius: BorderRadius.circular(AppDimens.mineGridRadius), ), child: ClipRRect( borderRadius: BorderRadius.circular(AppDimens.mineGridRadius), child: MediaQuery.withClampedTextScaling( maxScaleFactor: _gridMaxTextScale, child: Column( children: [ _row(items.take(_gridColumnCount).toList()), const _MineHorizontalDivider(), _row(items.skip(_gridColumnCount).toList()), ], ), ), ), ), ); } List<_MineActionItem> _primaryItems(AppLocalizations l10n) { return [ _MineActionItem( key: const Key('mine-wallet'), icon: Icons.account_balance_wallet_outlined, label: l10n.wallet, onTap: primaryActions.onWallet, ), _MineActionItem( key: const Key('mine-favorites'), icon: Icons.star_outline_rounded, label: l10n.myFavorites, onTap: primaryActions.onFavorites, ), _MineActionItem( key: const Key('mine-downloads'), icon: Icons.download_for_offline_outlined, label: l10n.offlineDownloads, onTap: primaryActions.onDownloads, ), _MineActionItem( key: const Key('mine-history'), icon: Icons.history_rounded, label: l10n.watchHistory, onTap: primaryActions.onHistory, ), ]; } List<_MineActionItem> _serviceItems(AppLocalizations l10n) { return [ _MineActionItem( key: const Key('mine-help'), icon: Icons.support_agent_outlined, label: l10n.contactSupport, onTap: () => serviceActions.onOpen(MineDestination.help), ), _MineActionItem( key: const Key('mine-language'), icon: Icons.language_rounded, label: l10n.language, onTap: serviceActions.onLanguage, ), _MineActionItem( key: const Key('mine-settings'), icon: Icons.settings_outlined, label: l10n.settings, onTap: () => serviceActions.onOpen(MineDestination.settings), ), _MineActionItem( key: const Key('mine-notices'), icon: Icons.notifications_none_rounded, label: l10n.notices, onTap: () => serviceActions.onOpen(MineDestination.notices), ), ]; } Widget _row(List<_MineActionItem> items) { return SizedBox( height: AppDimens.mineGridCellHeight, child: Row( children: [ for (var index = 0; index < items.length; index++) ...[ Expanded(child: _MineActionCell(item: items[index])), if (index < items.length - 1) const _MineVerticalDivider(), ], ], ), ); } } /// 宫格第一排的常用功能回调。 class MinePrimaryActions { const MinePrimaryActions({ required this.onWallet, required this.onFavorites, required this.onDownloads, required this.onHistory, }); final VoidCallback onWallet; final VoidCallback onFavorites; final VoidCallback onDownloads; final VoidCallback onHistory; } /// 宫格第二排的服务功能回调。 class MineServiceActions { const MineServiceActions({required this.onOpen, required this.onLanguage}); final ValueChanged onOpen; final VoidCallback onLanguage; } class _MineActionItem { const _MineActionItem({ required this.key, required this.icon, required this.label, required this.onTap, }); final Key key; final IconData icon; final String label; final VoidCallback onTap; Key get iconSurfaceKey => ValueKey('${(key as ValueKey).value}-icon-surface'); } class _MineActionCell extends StatelessWidget { const _MineActionCell({required this.item}); final _MineActionItem item; @override Widget build(BuildContext context) { return Material( color: AppColors.transparent, child: InkWell( key: item.key, onTap: item.onTap, child: AppPressScale( child: Semantics( button: true, label: item.label, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ _iconSurface(), const SizedBox(height: AppDimens.spaceSm), _label(), ], ), ), ), ), ); } Widget _iconSurface() { return Container( key: item.iconSurfaceKey, width: AppDimens.mineGridIconSurface, height: AppDimens.mineGridIconSurface, decoration: BoxDecoration( gradient: const RadialGradient( center: Alignment(-0.35, -0.45), radius: 0.95, colors: [ AppColors.mineOutline, AppColors.contentChip, AppColors.mineGridIconSurface, ], ), shape: BoxShape.circle, border: Border.all(color: AppColors.glassHairline), boxShadow: [ const BoxShadow( color: AppColors.shadowSoft, blurRadius: AppDimens.spaceSm, offset: Offset(0, AppDimens.spaceXs), ), BoxShadow( color: AppColors.brandRed.withValues(alpha: 0.12), blurRadius: AppDimens.spaceSm, ), ], ), child: Icon( item.icon, color: AppColors.mineGridIconAccent, size: AppDimens.mineGridIcon, ), ); } Widget _label() { return Text( item.label, maxLines: 2, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center, style: const TextStyle( color: AppColors.mineGridLabel, fontSize: AppDimens.mineGridLabel, fontWeight: FontWeight.w500, height: AppDimens.mineGridLabelLineHeight, ), ); } } class _MineVerticalDivider extends StatelessWidget { const _MineVerticalDivider(); @override Widget build(BuildContext context) { return Container( width: AppDimens.mineGridHairline, color: AppColors.mineGridDivider, ); } } class _MineHorizontalDivider extends StatelessWidget { const _MineHorizontalDivider(); @override Widget build(BuildContext context) { return Container( height: AppDimens.mineGridHairline, color: AppColors.mineGridDivider, ); } }