// Author: fruit.com.cn import 'package:flutter/material.dart'; import '../../../core/theme/app_colors.dart'; import '../../../core/theme/app_dimens.dart'; import '../../../l10n/app_localizations.dart'; import '../mine_types.dart'; const double _vipRadius = 12; const double _vipBadgeSize = 36; const double _vipButtonHeight = 34; /// 金色会员横幅。 class MineVipBanner extends StatelessWidget { const MineVipBanner({super.key, required this.onOpen}); final VoidCallback onOpen; @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; return Container( key: const Key('mine-vip'), decoration: BoxDecoration( gradient: const LinearGradient( colors: [AppColors.vipGoldStart, AppColors.vipGoldEnd], ), borderRadius: BorderRadius.circular(_vipRadius), ), child: Material( color: AppColors.transparent, borderRadius: BorderRadius.circular(_vipRadius), clipBehavior: Clip.antiAlias, child: InkWell( onTap: onOpen, child: Padding( padding: const EdgeInsets.symmetric( horizontal: AppDimens.cardPadding, vertical: AppDimens.spaceMd, ), child: Row( children: [ Container( width: _vipBadgeSize, height: _vipBadgeSize, decoration: const BoxDecoration( color: AppColors.vipBadgeSurface, shape: BoxShape.circle, ), child: const Icon( Icons.workspace_premium_rounded, color: AppColors.onGold, size: 22, ), ), const SizedBox(width: AppDimens.spaceMd), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( l10n.vipBrandName, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle( color: AppColors.onGold, fontSize: AppDimens.sectionTitle, fontWeight: FontWeight.w700, ), ), const SizedBox(height: 2), Text( l10n.mineVipSubtitle, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle( color: AppColors.onGold, fontSize: AppDimens.caption, ), ), ], ), ), const SizedBox(width: AppDimens.spaceSm), TextButton( key: const Key('mine-vip-open'), onPressed: onOpen, style: TextButton.styleFrom( minimumSize: const Size(0, _vipButtonHeight), padding: const EdgeInsets.symmetric( horizontal: AppDimens.spaceMd, ), backgroundColor: AppColors.onGold, foregroundColor: AppColors.textPrimary, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(_vipButtonHeight), ), ), child: Text(l10n.joinVip), ), ], ), ), ), ), ); } } /// 「我的」页单列功能菜单。 class MineMenuList extends StatelessWidget { const MineMenuList({ super.key, required this.onOpen, required this.onLanguage, required this.languageLabel, }); final ValueChanged onOpen; final VoidCallback onLanguage; final String languageLabel; @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; return Container( key: const Key('mine-menu'), decoration: BoxDecoration( color: AppColors.mineCard, borderRadius: BorderRadius.circular(AppDimens.mineCardRadius), border: Border.all(color: AppColors.contentBorder), ), child: Material( color: AppColors.transparent, borderRadius: BorderRadius.circular(AppDimens.mineCardRadius), clipBehavior: Clip.antiAlias, child: Column( children: [ _row( key: const Key('mine-wallet'), icon: Icons.account_balance_wallet_outlined, title: l10n.wallet, destination: MineDestination.wallet, ), _divider(), _row( key: const Key('mine-downloads'), icon: Icons.download_outlined, title: l10n.offlineDownloads, destination: MineDestination.downloads, ), _divider(), _row( key: const Key('mine-history'), icon: Icons.history_rounded, title: l10n.watchHistory, destination: MineDestination.history, ), _divider(), _row( key: const Key('mine-watch-preferences'), icon: Icons.tune_rounded, title: l10n.watchPreferences, destination: MineDestination.preferences, ), _divider(), _row( key: const Key('mine-help'), icon: Icons.support_agent_rounded, title: l10n.contactSupport, destination: MineDestination.help, ), _divider(), _languageRow(l10n), _divider(), _row( key: const Key('mine-settings'), icon: Icons.settings_outlined, title: l10n.settings, destination: MineDestination.settings, ), ], ), ), ); } Widget _languageRow(AppLocalizations l10n) { return ListTile( key: const Key('mine-language'), minTileHeight: AppDimens.mineRowHeight, contentPadding: const EdgeInsets.symmetric(horizontal: AppDimens.spaceLg), leading: const Icon( Icons.language_rounded, color: AppColors.textPrimary, size: AppDimens.mineMenuIcon, ), title: Text( l10n.language, style: const TextStyle( color: AppColors.textPrimary, fontSize: AppDimens.listTitle, fontWeight: FontWeight.w500, ), ), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ Text( languageLabel, style: const TextStyle( color: AppColors.textSecondary, fontSize: AppDimens.caption, ), ), const SizedBox(width: AppDimens.spaceXs), const Icon( Icons.chevron_right_rounded, color: AppColors.textSecondary, size: 18, ), ], ), onTap: onLanguage, ); } Widget _row({ required Key key, required IconData icon, required String title, required MineDestination destination, }) { return ListTile( key: key, minTileHeight: AppDimens.mineRowHeight, contentPadding: const EdgeInsets.symmetric(horizontal: AppDimens.spaceLg), leading: Icon( icon, color: AppColors.textPrimary, size: AppDimens.mineMenuIcon, ), title: Text( title, style: const TextStyle( color: AppColors.textPrimary, fontSize: AppDimens.listTitle, fontWeight: FontWeight.w500, ), ), trailing: const Icon( Icons.chevron_right_rounded, color: AppColors.textSecondary, size: 18, ), onTap: () => onOpen(destination), ); } Widget _divider() { return const Divider( height: 1, indent: AppDimens.spaceLg, endIndent: AppDimens.spaceLg, color: AppColors.contentSurface, ); } }