fix(ui): 打磨推荐追剧我的设置页间距与图标
This commit is contained in:
1 parent
de7da64886
commit
5346be40a9
33 files changed
+1408
-811
No files matched your search
@@ -1,6 +1,7 @@
|
||||
// Author: fruit.com.cn
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
@@ -13,8 +14,7 @@ import '../../../core/widgets/centered_toast.dart';
|
||||
import '../../../core/widgets/remote_image.dart';
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
|
||||
const double _buttonHeight = 34;
|
||||
const double _buttonRadius = 6;
|
||||
const double _buttonHeight = 40;
|
||||
|
||||
/// 「我的」页用户区。
|
||||
class MineHeader extends StatelessWidget {
|
||||
@@ -35,7 +35,7 @@ class MineHeader extends StatelessWidget {
|
||||
final uid = signedIn ? user?.uid.trim() ?? '' : '';
|
||||
return Padding(
|
||||
key: const Key('mine-user-row'),
|
||||
padding: const EdgeInsets.symmetric(vertical: AppDimens.spaceMd),
|
||||
padding: const EdgeInsets.symmetric(vertical: AppDimens.spaceSm),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
@@ -55,7 +55,7 @@ class MineHeader extends StatelessWidget {
|
||||
fontFamily: 'Outfit',
|
||||
color: AppColors.textPrimary,
|
||||
fontSize: AppDimens.mineUserName,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontWeight: FontWeight.w400,
|
||||
height: AppDimens.mineUserNameLineHeight,
|
||||
),
|
||||
),
|
||||
@@ -121,18 +121,29 @@ class MineHeader extends StatelessWidget {
|
||||
key: const Key('mine-avatar'),
|
||||
width: AppDimens.mineAvatar,
|
||||
height: AppDimens.mineAvatar,
|
||||
decoration: const BoxDecoration(
|
||||
color: AppColors.contentSurface,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: AppColors.textTertiary,
|
||||
width: 1.2,
|
||||
),
|
||||
),
|
||||
child: ClipOval(
|
||||
child: BackdropFilter(
|
||||
filter: ui.ImageFilter.blur(sigmaX: 10, sigmaY: 10),
|
||||
child: Container(
|
||||
color: AppColors.textPrimary.withValues(alpha: 0.06),
|
||||
alignment: Alignment.center,
|
||||
child: path.isEmpty
|
||||
? const Icon(
|
||||
Icons.person_outline_rounded,
|
||||
color: AppColors.textPrimary,
|
||||
size: 30,
|
||||
)
|
||||
: RemoteImage(path, fit: BoxFit.cover),
|
||||
),
|
||||
),
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: path.isEmpty
|
||||
? const Icon(
|
||||
Icons.person_rounded,
|
||||
color: AppColors.textPrimary,
|
||||
size: 28,
|
||||
)
|
||||
: RemoteImage(path, fit: BoxFit.cover),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -141,20 +152,20 @@ class MineHeader extends StatelessWidget {
|
||||
required String label,
|
||||
required VoidCallback onTap,
|
||||
}) {
|
||||
return OutlinedButton(
|
||||
return TextButton(
|
||||
key: key,
|
||||
onPressed: onTap,
|
||||
style: OutlinedButton.styleFrom(
|
||||
style: TextButton.styleFrom(
|
||||
minimumSize: const Size(0, _buttonHeight),
|
||||
padding: const EdgeInsets.symmetric(horizontal: AppDimens.spaceMd),
|
||||
foregroundColor: AppColors.textPrimary,
|
||||
side: const BorderSide(color: AppColors.mineOutline),
|
||||
backgroundColor: AppColors.brandRed,
|
||||
foregroundColor: AppColors.onPrimary,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(_buttonRadius),
|
||||
borderRadius: BorderRadius.circular(_buttonHeight / 2),
|
||||
),
|
||||
textStyle: const TextStyle(
|
||||
fontSize: AppDimens.body,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
|
||||
@@ -7,11 +7,9 @@ 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;
|
||||
const double _vipRadius = 14;
|
||||
|
||||
/// 金色会员横幅。
|
||||
/// 「我的」页金色 VIP 卡:品牌行 + 立即开通 + 2×2 权益宫格。
|
||||
class MineVipBanner extends StatelessWidget {
|
||||
const MineVipBanner({super.key, required this.onOpen});
|
||||
|
||||
@@ -24,7 +22,9 @@ class MineVipBanner extends StatelessWidget {
|
||||
key: const Key('mine-vip'),
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [AppColors.vipGoldStart, AppColors.vipGoldEnd],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [AppColors.vipCardStart, AppColors.vipCardEnd],
|
||||
),
|
||||
borderRadius: BorderRadius.circular(_vipRadius),
|
||||
),
|
||||
@@ -35,69 +35,89 @@ class MineVipBanner extends StatelessWidget {
|
||||
child: InkWell(
|
||||
onTap: onOpen,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: AppDimens.cardPadding,
|
||||
vertical: AppDimens.spaceMd,
|
||||
padding: const EdgeInsets.fromLTRB(
|
||||
AppDimens.cardPadding,
|
||||
AppDimens.spaceSm + 2,
|
||||
AppDimens.cardPadding,
|
||||
AppDimens.spaceSm + 2,
|
||||
),
|
||||
child: Row(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
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(
|
||||
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: AppDimens.sectionTitle,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
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),
|
||||
_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(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,
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
backgroundColor: AppColors.onGold,
|
||||
foregroundColor: AppColors.textPrimary,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(_vipButtonHeight),
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Text(l10n.joinVip),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -106,184 +126,256 @@ class MineVipBanner extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 「我的」页 4 列功能入口。
|
||||
class MineMenuList extends StatelessWidget {
|
||||
const MineMenuList({
|
||||
/// 快捷图标行:钱包 / 我的收藏 / 离线缓存 / 播放历史(设计稿的「奖励」暂不做)。
|
||||
class MineQuickActions extends StatelessWidget {
|
||||
const MineQuickActions({
|
||||
super.key,
|
||||
required this.onOpen,
|
||||
required this.onLanguage,
|
||||
required this.onWallet,
|
||||
required this.onFavorites,
|
||||
required this.onDownloads,
|
||||
required this.onHistory,
|
||||
});
|
||||
|
||||
final ValueChanged<MineDestination> onOpen;
|
||||
final VoidCallback onLanguage;
|
||||
final VoidCallback onWallet;
|
||||
final VoidCallback onFavorites;
|
||||
final VoidCallback onDownloads;
|
||||
final VoidCallback onHistory;
|
||||
|
||||
@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,
|
||||
),
|
||||
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: [
|
||||
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),
|
||||
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,
|
||||
),
|
||||
_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),
|
||||
if (value != null && value.isNotEmpty) ...[
|
||||
const SizedBox(width: AppDimens.spaceSm),
|
||||
Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
color: AppColors.textTertiary,
|
||||
fontSize: AppDimens.mineServiceValueFont,
|
||||
),
|
||||
_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,
|
||||
actionKey: const Key('mine-notices'),
|
||||
icon: Icons.notifications_none_rounded,
|
||||
iconColor: AppColors.mineIconNotices,
|
||||
label: l10n.notices,
|
||||
onTap: () => onOpen(MineDestination.notices),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
const SizedBox(width: AppDimens.spaceXs),
|
||||
const Icon(
|
||||
Icons.chevron_right_rounded,
|
||||
color: AppColors.textSecondary,
|
||||
size: 22,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
// 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';
|
||||
|
||||
class MineMoreServices extends StatelessWidget {
|
||||
const MineMoreServices({
|
||||
super.key,
|
||||
required this.onCommonQuestions,
|
||||
required this.onAbout,
|
||||
});
|
||||
|
||||
final VoidCallback onCommonQuestions;
|
||||
final VoidCallback onAbout;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return Container(
|
||||
key: const Key('mine-more-services'),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.minePanelSurface,
|
||||
borderRadius: BorderRadius.circular(AppDimens.mineGridRadius),
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: Column(
|
||||
children: [
|
||||
_row(
|
||||
key: const Key('mine-common-questions'),
|
||||
label: l10n.commonQuestions,
|
||||
onTap: onCommonQuestions,
|
||||
),
|
||||
const Divider(
|
||||
height: AppDimens.mineGridDividerWidth,
|
||||
thickness: AppDimens.mineGridDividerWidth,
|
||||
color: AppColors.mineMoreDivider,
|
||||
),
|
||||
_row(
|
||||
key: const Key('mine-about'),
|
||||
label: l10n.aboutUs,
|
||||
onTap: onAbout,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _row({
|
||||
required Key key,
|
||||
required String label,
|
||||
required VoidCallback onTap,
|
||||
}) {
|
||||
return Material(
|
||||
color: AppColors.transparent,
|
||||
child: InkWell(
|
||||
key: key,
|
||||
onTap: onTap,
|
||||
child: SizedBox(
|
||||
height: AppDimens.mineMoreRowHeight,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: AppDimens.minePanelPadding,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
label,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: AppColors.textPrimary,
|
||||
fontSize: AppDimens.mineMoreFont,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Icon(
|
||||
Icons.chevron_right_rounded,
|
||||
color: AppColors.textSecondary,
|
||||
size: 18,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user