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

283 lines
9.7 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 = 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),
),
],
),
),
),
),
);
}
}
/// 「我的」页 4 列功能入口。
class MineMenuList extends StatelessWidget {
const MineMenuList({
super.key,
required this.onOpen,
required this.onLanguage,
});
final ValueChanged<MineDestination> onOpen;
final VoidCallback onLanguage;
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Container(
key: const Key('mine-menu'),
decoration: BoxDecoration(
color: AppColors.mineGridSurface,
borderRadius: BorderRadius.circular(AppDimens.mineGridRadius),
),
child: Material(
color: AppColors.transparent,
borderRadius: BorderRadius.circular(AppDimens.mineGridRadius),
clipBehavior: Clip.antiAlias,
child: Table(
key: const Key('mine-menu-grid'),
defaultColumnWidth: const FlexColumnWidth(),
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
border: const TableBorder(
horizontalInside: BorderSide(
color: AppColors.mineGridDivider,
width: AppDimens.mineGridDividerWidth,
),
verticalInside: BorderSide(
color: AppColors.mineGridDivider,
width: AppDimens.mineGridDividerWidth,
),
),
children: [
TableRow(
children: [
_cell(
index: 0,
actionKey: const Key('mine-wallet'),
icon: Icons.account_balance_wallet_outlined,
iconColor: AppColors.mineIconWallet,
label: l10n.wallet,
onTap: () => onOpen(MineDestination.wallet),
),
_cell(
index: 1,
actionKey: const Key('mine-downloads'),
icon: Icons.download_outlined,
iconColor: AppColors.mineIconDownloads,
label: l10n.offlineDownloads,
onTap: () => onOpen(MineDestination.downloads),
),
_cell(
index: 2,
actionKey: const Key('mine-history'),
icon: Icons.history_rounded,
iconColor: AppColors.mineIconHistory,
label: l10n.watchHistory,
onTap: () => onOpen(MineDestination.history),
),
_cell(
index: 3,
actionKey: const Key('mine-watch-preferences'),
icon: Icons.tune_rounded,
iconColor: AppColors.mineIconPreferences,
label: l10n.watchPreferences,
onTap: () => onOpen(MineDestination.preferences),
),
],
),
TableRow(
children: [
_cell(
index: 4,
actionKey: const Key('mine-help'),
icon: Icons.support_agent_rounded,
iconColor: AppColors.mineIconSupport,
label: l10n.contactSupport,
onTap: () => onOpen(MineDestination.help),
),
_cell(
index: 5,
actionKey: const Key('mine-language'),
icon: Icons.language_rounded,
iconColor: AppColors.mineIconLanguage,
label: l10n.language,
onTap: onLanguage,
),
_cell(
index: 6,
actionKey: const Key('mine-settings'),
icon: Icons.settings_outlined,
iconColor: AppColors.mineIconSettings,
label: l10n.settings,
onTap: () => onOpen(MineDestination.settings),
),
_cell(index: 7),
],
),
],
),
),
);
}
Widget _cell({
required int index,
Key? actionKey,
IconData? icon,
Color? iconColor,
String? label,
VoidCallback? onTap,
}) {
return SizedBox(
key: Key('mine-menu-cell-$index'),
height: AppDimens.mineGridCellHeight,
child: actionKey == null
? const SizedBox.shrink()
: InkWell(
key: actionKey,
onTap: onTap,
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: AppDimens.mineGridIconSurface,
height: AppDimens.mineGridIconSurface,
decoration: const BoxDecoration(
color: AppColors.mineGridIconSurface,
shape: BoxShape.circle,
),
child: DecoratedBox(
decoration: BoxDecoration(
color: iconColor?.withValues(alpha: 0.08),
shape: BoxShape.circle,
),
child: Icon(
icon,
color: iconColor,
size: AppDimens.mineGridIcon,
),
),
),
const SizedBox(height: AppDimens.spaceXs + 2),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4),
child: Text(
label ?? '',
maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
style: const TextStyle(
color: AppColors.mineGridLabel,
fontSize: AppDimens.mineGridLabel,
fontWeight: FontWeight.w500,
height: 1.2,
),
),
),
],
),
),
),
);
}
}