Files
ReelShort/lib/pages/mine/widgets/mine_menu.dart
T

382 lines
12 KiB
Dart

// 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 = 14;
/// 「我的」页金色 VIP 卡:品牌行 + 立即开通 + 2×2 权益宫格。
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(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [AppColors.vipCardStart, AppColors.vipCardEnd],
),
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.fromLTRB(
AppDimens.cardPadding,
AppDimens.spaceSm + 2,
AppDimens.cardPadding,
AppDimens.spaceSm + 2,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
const Icon(
Icons.diamond_outlined,
color: AppColors.onGold,
size: 24,
),
const SizedBox(width: AppDimens.spaceSm),
Expanded(
child: Text(
l10n.vipBrandName,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: AppColors.onGold,
fontSize: 18,
fontWeight: FontWeight.w400,
),
),
),
const SizedBox(width: AppDimens.spaceSm),
_openButton(l10n),
],
),
Transform.translate(
offset: const Offset(0, -7),
child: Text(
l10n.mineVipSubtitle,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: AppColors.onGold.withValues(alpha: 0.7),
fontSize: AppDimens.caption,
),
),
),
const SizedBox(height: AppDimens.mineVipBenefitRowGap),
Container(
height: 1,
color: AppColors.onGold.withValues(alpha: 0.15),
),
const SizedBox(height: AppDimens.mineVipBenefitRowGap),
Table(
defaultColumnWidth: const FlexColumnWidth(),
children: [
TableRow(
children: [
_benefit(
key: const Key('mine-vip-benefit-0'),
icon: Icons.play_circle_outline_rounded,
label: l10n.vipBenefitFree,
),
_benefit(
key: const Key('mine-vip-benefit-1'),
icon: Icons.ads_click_rounded,
label: l10n.vipBenefitNoAds,
),
],
),
TableRow(
children: [
_benefit(
key: const Key('mine-vip-benefit-2'),
icon: Icons.hd_outlined,
label: l10n.vipBenefitHd,
),
_benefit(
key: const Key('mine-vip-benefit-3'),
icon: Icons.download_for_offline_outlined,
label: l10n.vipBenefitFastCache,
),
],
),
],
),
],
),
),
),
),
);
}
Widget _openButton(AppLocalizations l10n) {
return TextButton(
key: const Key('mine-vip-open'),
onPressed: onOpen,
style: TextButton.styleFrom(
minimumSize: const Size(0, AppDimens.mineVipButtonHeight),
padding: const EdgeInsets.symmetric(horizontal: AppDimens.spaceMd),
backgroundColor: AppColors.onGold,
foregroundColor: AppColors.vipGoldStart,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
AppDimens.mineVipButtonHeight / 2,
),
),
textStyle: const TextStyle(
fontSize: AppDimens.body,
fontWeight: FontWeight.w400,
),
),
child: Text(l10n.vipOpenNow),
);
}
Widget _benefit({required Key key, required IconData icon, required String label}) {
return Padding(
key: key,
padding: const EdgeInsets.symmetric(vertical: AppDimens.mineVipBenefitRowGap),
child: Row(
children: [
Container(
width: AppDimens.mineVipBenefitBox,
height: AppDimens.mineVipBenefitBox,
decoration: BoxDecoration(
border: Border.all(
color: AppColors.onGold.withValues(alpha: 0.6),
width: 1.2,
),
borderRadius: BorderRadius.circular(
AppDimens.mineVipBenefitBoxRadius,
),
),
child: Icon(
icon,
color: AppColors.onGold,
size: AppDimens.mineVipBenefitGlyph,
),
),
const SizedBox(width: AppDimens.spaceSm),
Expanded(
child: Text(
label,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: AppColors.onGold,
fontSize: AppDimens.mineVipBenefitFont,
),
),
),
],
),
);
}
}
/// 快捷图标行:钱包 / 我的收藏 / 离线缓存 / 播放历史(设计稿的「奖励」暂不做)。
class MineQuickActions extends StatelessWidget {
const MineQuickActions({
super.key,
required this.onWallet,
required this.onFavorites,
required this.onDownloads,
required this.onHistory,
});
final VoidCallback onWallet;
final VoidCallback onFavorites;
final VoidCallback onDownloads;
final VoidCallback onHistory;
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Row(
children: [
_action(
key: const Key('mine-wallet'),
icon: Icons.wallet_outlined,
label: l10n.wallet,
onTap: onWallet,
),
_action(
key: const Key('mine-favorites'),
icon: Icons.star_border_rounded,
label: l10n.myFavorites,
onTap: onFavorites,
),
_action(
key: const Key('mine-downloads'),
icon: Icons.download_outlined,
label: l10n.offlineDownloads,
onTap: onDownloads,
),
_action(
key: const Key('mine-history'),
icon: Icons.history_rounded,
label: l10n.watchHistory,
onTap: onHistory,
),
],
);
}
Widget _action({
required Key key,
required IconData icon,
required String label,
required VoidCallback onTap,
}) {
return Expanded(
child: InkWell(
key: key,
onTap: onTap,
borderRadius: BorderRadius.circular(10),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: AppDimens.spaceSm),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, color: AppColors.textPrimary, size: AppDimens.mineQuickActionIcon),
const SizedBox(height: AppDimens.mineQuickActionGap),
Text(
label,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: AppColors.textPrimary,
fontSize: AppDimens.mineQuickActionLabelFont,
),
),
],
),
),
),
);
}
}
/// 「更多服务」列表行:白图标 + 标题 + 可选值 + chevron,行间细分隔线。
class MineServiceList extends StatelessWidget {
const MineServiceList({
super.key,
required this.onOpen,
required this.onLanguage,
required this.languageName,
});
final ValueChanged<MineDestination> onOpen;
final VoidCallback onLanguage;
final String languageName;
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
final rows = <Widget>[
_row(
key: const Key('mine-help'),
icon: Icons.headset_outlined,
label: l10n.contactSupport,
onTap: () => onOpen(MineDestination.help),
),
_divider(),
_row(
key: const Key('mine-language'),
icon: Icons.language_rounded,
label: l10n.language,
value: languageName,
onTap: onLanguage,
),
_divider(),
_row(
key: const Key('mine-settings'),
icon: Icons.settings_outlined,
label: l10n.settings,
onTap: () => onOpen(MineDestination.settings),
),
_divider(),
_row(
key: const Key('mine-notices'),
icon: Icons.notifications_none_rounded,
label: l10n.notices,
onTap: () => onOpen(MineDestination.notices),
),
];
return Column(key: const Key('mine-menu'), children: rows);
}
Widget _divider() => const Divider(
height: AppDimens.mineGridDividerWidth,
thickness: AppDimens.mineGridDividerWidth,
color: AppColors.contentBorder,
);
Widget _row({
required Key key,
required IconData icon,
required String label,
String? value,
required VoidCallback onTap,
}) {
return SizedBox(
height: AppDimens.mineServiceRowHeight,
child: InkWell(
key: key,
onTap: onTap,
child: Row(
children: [
Icon(icon, color: AppColors.textPrimary, size: AppDimens.mineServiceIcon),
const SizedBox(width: AppDimens.spaceMd),
Expanded(
child: Text(
label,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: AppColors.textPrimary,
fontSize: AppDimens.mineServiceTitleFont,
),
),
),
if (value != null && value.isNotEmpty) ...[
const SizedBox(width: AppDimens.spaceSm),
Text(
value,
style: const TextStyle(
color: AppColors.textTertiary,
fontSize: AppDimens.mineServiceValueFont,
),
),
],
const SizedBox(width: AppDimens.spaceXs),
const Icon(
Icons.chevron_right_rounded,
color: AppColors.textSecondary,
size: 22,
),
],
),
),
);
}
}