fix(ui): 打磨推荐追剧我的设置页间距与图标
This commit is contained in:
1 parent
de7da64886
commit
5346be40a9
33 files changed
+1408
-811
No files matched your search
@@ -27,13 +27,13 @@ abstract final class AppColors {
|
||||
static const overlaySecondary = Color(0xFFC7C7CC);
|
||||
static const overlayLabel = Color(0xFFE6E6EB);
|
||||
|
||||
/// 主操作、选中态、播放进度(品牌橙)。
|
||||
static const blue = Color(0xFFFF6B2C);
|
||||
/// 主操作、选中态、播放进度。旧品牌橙已全量映射为品牌红(2026-10 改版)。
|
||||
static const blue = Color(0xFFF04E4E);
|
||||
static const primary = blue;
|
||||
static const actionRed = Color(0xFFFF3B30);
|
||||
|
||||
/// 主操作按下态。
|
||||
static const bluePressed = Color(0xFFE55A1F);
|
||||
static const bluePressed = Color(0xFFD64040);
|
||||
|
||||
/// 链接与次要高亮:统一改用中性浅灰,避免旧青色残留。
|
||||
static const blueSoft = Color(0xFFB0B0B0);
|
||||
@@ -47,6 +47,10 @@ abstract final class AppColors {
|
||||
static const homeGiftPink = Color(0xFFFF4D8D);
|
||||
static const vipGoldStart = Color(0xFFF5D9A0);
|
||||
static const vipGoldEnd = Color(0xFFE8B65A);
|
||||
|
||||
/// 「我的」页 VIP 卡的浅香槟金(见设计稿,接近纯色)。
|
||||
static const vipCardStart = Color(0xFFF6E8C6);
|
||||
static const vipCardEnd = Color(0xFFEDD9A8);
|
||||
static const vipBadgeSurface = Color(0x1F3D2408);
|
||||
static const bronze = Color(0xFFCD7F32);
|
||||
static const bronzeDeep = Color(0xFFA9713A);
|
||||
@@ -75,6 +79,15 @@ abstract final class AppColors {
|
||||
/// 首页/追剧/我的统一的纯黑内容背景。
|
||||
static const appBackground = Color(0xFF000000);
|
||||
|
||||
/// 追剧页顶部的暗红光晕,向下淡入纯黑(见设计稿)。
|
||||
static const followingGlow = Color(0xFF4C161A);
|
||||
|
||||
/// 光晕的过渡色:让暖色维持更久再压黑。
|
||||
static const followingGlowMid = Color(0xFF1E0B0C);
|
||||
|
||||
/// 继续观看横幅剧名的暖白(见设计稿,非纯白)。
|
||||
static const bannerTitleWarm = Color(0xFFF5EFE4);
|
||||
|
||||
/// 中性深灰卡片与控件表面。
|
||||
static const contentCard = Color(0xFF16161A);
|
||||
static const contentSurface = Color(0xFF1C1C1E);
|
||||
@@ -96,7 +109,7 @@ abstract final class AppColors {
|
||||
static const mineGradientTop = Color(0xFF3A1B0E);
|
||||
static const mineGradientMiddle = Color(0xFF1A0C07);
|
||||
static const mineGradientBottom = Color(0xFF000000);
|
||||
static const mineGradientGlow = Color(0x33FF6B2C);
|
||||
static const mineGradientGlow = Color(0x33F04E4E);
|
||||
static const mineGridSurface = Color(0x99101010);
|
||||
static const minePanelSurface = Color(0xFF101010);
|
||||
static const mineMoreDivider = Color(0xFF1C1C1E);
|
||||
@@ -111,7 +124,7 @@ abstract final class AppColors {
|
||||
static const mineIconLanguage = Color(0xFF22D3EE);
|
||||
static const mineIconSettings = Color(0xFFA1A1AA);
|
||||
static const mineIconNotices = Color(0xFFFF8A4C);
|
||||
static const recommendPlaylistGlow = Color(0x26FF6B2C);
|
||||
static const recommendPlaylistGlow = Color(0x26F04E4E);
|
||||
|
||||
/// 次级文字与列表 chevron。
|
||||
static const textPrimary = Color(0xFFFFFFFF);
|
||||
@@ -136,6 +149,7 @@ abstract final class AppColors {
|
||||
/// 底部导航专用:纯黑背景、选中品牌红与未选中白。
|
||||
static const navBackground = Color(0xFF000000);
|
||||
static const brandRed = Color(0xFFF04E4E);
|
||||
static const brandRedPressed = Color(0xFFD64040);
|
||||
static const navSelected = brandRed;
|
||||
|
||||
/// 卡片阴影(深色几乎不用阴影)。
|
||||
@@ -214,7 +228,7 @@ abstract final class AppColors {
|
||||
static const bannerScrimEnd = Color(0xE6000000);
|
||||
|
||||
/// 票券虚线等主色描边。
|
||||
static const primaryBorder = Color(0x66FF6B2C);
|
||||
static const primaryBorder = Color(0x66F04E4E);
|
||||
|
||||
static const outlineDark = border;
|
||||
static const outlineVariantDark = border;
|
||||
|
||||
@@ -146,10 +146,12 @@ abstract final class AppDimens {
|
||||
static const double homeActionGap = 6;
|
||||
|
||||
/// 推荐分区。
|
||||
static const double recommendSectionGap = 12;
|
||||
static const double recommendSectionTitle = 17;
|
||||
static const double recommendSectionSubtitle = 11;
|
||||
static const double recommendSectionMore = 12;
|
||||
static const double recommendRowHeight = 252;
|
||||
// 封面 122*(4/3)≈163 + 间距6 + 两行标题39 + 间距6 + 标签13 ≈ 227。
|
||||
static const double recommendRowHeight = 228;
|
||||
static const double recommendCardWidth = 122;
|
||||
|
||||
/// 首页热播榜。
|
||||
@@ -169,25 +171,26 @@ abstract final class AppDimens {
|
||||
|
||||
/// 全部短剧筛选与追剧双列。
|
||||
static const double filterChipFont = 16;
|
||||
static const double filterChipHeight = 32;
|
||||
static const double filterChipRadius = 16;
|
||||
static const double filterChipHeight = 28;
|
||||
static const double filterChipRadius = 14;
|
||||
static const double filterChipHorizontalPadding = 12;
|
||||
static const double filterRowGap = 6;
|
||||
static const double filterItemGap = 10;
|
||||
static const double allDramasHorizontal = 12;
|
||||
static const double allDramasGridGap = 6;
|
||||
static const double allDramasGridRowGap = 12;
|
||||
static const double allDramasGridRowGap = 6;
|
||||
static const double allDramasFilterToGridGap = 12;
|
||||
static const double followingHeaderHeight = 52;
|
||||
static const double followingTabFont = 18;
|
||||
static const double followingTabGap = 24;
|
||||
static const double followingEditIconSize = 20;
|
||||
static const double followingEditHitSize = 40;
|
||||
static const double followingAddIconSize = 28;
|
||||
static const double followingAddIconSize = 20;
|
||||
static const double followingAddIconStroke = 1.5;
|
||||
static const double followingGridGap = 6;
|
||||
static const double followingGridRowGap = 12;
|
||||
static const double followingCardTextExtent = 70;
|
||||
// 单行标题 16*1.3 + 间距 6+4 + 副标题约 16 ≈ 47。
|
||||
static const double followingCardTextExtent = 48;
|
||||
static const double followingSubtitleFont = 12;
|
||||
static const double followingSubtitleGap = 4;
|
||||
static const double followingProgressHeight = 2;
|
||||
@@ -201,6 +204,47 @@ abstract final class AppDimens {
|
||||
static const double followingHistoryProgressGap = 8;
|
||||
static const double followingHistoryLabelGap = 4;
|
||||
static const double followingHistoryActionHeight = 28;
|
||||
|
||||
/// 追剧页新版头部与收藏布局。
|
||||
static const double followingTitleFont = 26;
|
||||
static const double followingTitleRowHeight = 42;
|
||||
static const double followingTitleTopGap = 8;
|
||||
static const double followingSearchIcon = 26;
|
||||
static const double followingManageFont = 16;
|
||||
static const double followingHeaderActionGap = 8;
|
||||
static const double followingSegmentFont = 16;
|
||||
static const double followingSegmentGap = 28;
|
||||
static const double followingSegmentRowHeight = 42;
|
||||
static const double followingSegmentIndicatorWidth = 24;
|
||||
static const double followingSegmentIndicatorHeight = 3;
|
||||
static const double followingSegmentIndicatorRadius = 2;
|
||||
static const double followingSegmentIndicatorTopGap = 6;
|
||||
static const double followingBannerHeight = 176;
|
||||
static const double followingBannerRadius = 16;
|
||||
static const double followingBannerEdgeGap = 16;
|
||||
static const double followingBannerInnerGap = 16;
|
||||
static const double followingBannerTitleFont = 22;
|
||||
static const double followingBannerSubtitleFont = 13;
|
||||
static const double followingBannerMetaGap = 8;
|
||||
static const double followingBannerButtonHeight = 40;
|
||||
static const double followingBannerButtonRadius = 20;
|
||||
static const double followingBannerButtonFont = 15;
|
||||
static const double followingBannerButtonIcon = 18;
|
||||
static const double followingBannerButtonGap = 6;
|
||||
static const double followingBannerButtonHorizontalPadding = 20;
|
||||
static const double followingBannerButtonTopGap = 14;
|
||||
static const double followingBannerProgressHeight = 3;
|
||||
static const double followingSectionTitleFont = 16;
|
||||
static const double followingSectionCountFont = 13;
|
||||
static const double followingSectionTopGap = 20;
|
||||
static const double followingSectionBottomGap = 12;
|
||||
static const double followingCardTitleFontNew = 16;
|
||||
static const double followingCardSubtitleFontNew = 13;
|
||||
static const double followingBadgeFont = 11;
|
||||
static const double followingBadgeRadius = 6;
|
||||
static const double followingBadgeInset = 8;
|
||||
static const double followingBadgePaddingH = 8;
|
||||
static const double followingBadgePaddingV = 3;
|
||||
static const Duration followingTabAnimationDuration = Duration(
|
||||
milliseconds: 180,
|
||||
);
|
||||
@@ -211,8 +255,8 @@ abstract final class AppDimens {
|
||||
/// 「我的」页中性视觉。
|
||||
static const double mineCardRadius = 16;
|
||||
static const double mineSectionTitle = 15;
|
||||
static const double mineAvatar = 56;
|
||||
static const double mineUserName = 20;
|
||||
static const double mineAvatar = 64;
|
||||
static const double mineUserName = 24;
|
||||
static const double mineUserNameLineHeight = 1.15;
|
||||
static const double mineUserNameUidGap = 2;
|
||||
static const double mineUid = 12;
|
||||
@@ -227,7 +271,23 @@ abstract final class AppDimens {
|
||||
static const double mineGridDividerWidth = 1;
|
||||
static const double mineSectionTitleFont = 16;
|
||||
static const double mineSectionLinkFont = 12;
|
||||
static const double mineSectionGap = 20;
|
||||
static const double mineSectionGap = 12;
|
||||
|
||||
/// 「我的」页新版:快捷图标行与服务列表。
|
||||
static const double mineQuickActionIcon = 28;
|
||||
static const double mineQuickActionLabelFont = 14;
|
||||
static const double mineQuickActionGap = 8;
|
||||
static const double mineServiceRowHeight = 56;
|
||||
static const double mineServiceIcon = 24;
|
||||
static const double mineServiceTitleFont = 16;
|
||||
static const double mineServiceValueFont = 14;
|
||||
static const double mineVipBenefitFont = 14;
|
||||
static const double mineVipBenefitIcon = 20;
|
||||
static const double mineVipBenefitBox = 30;
|
||||
static const double mineVipBenefitBoxRadius = 7;
|
||||
static const double mineVipBenefitGlyph = 17;
|
||||
static const double mineVipBenefitRowGap = 4;
|
||||
static const double mineVipButtonHeight = 36;
|
||||
static const double mineContinueCardWidth = 96;
|
||||
static const double mineContinueRowHeight = 172;
|
||||
static const double mineContinueTitleFont = 13;
|
||||
|
||||
@@ -40,7 +40,7 @@ abstract final class AppTheme {
|
||||
/// 全局深色主题。
|
||||
static ThemeData dark() {
|
||||
const scheme = ColorScheme.dark(
|
||||
primary: AppColors.blue,
|
||||
primary: AppColors.brandRed,
|
||||
onPrimary: AppColors.onPrimary,
|
||||
secondary: AppColors.secondary,
|
||||
onSecondary: AppColors.ink,
|
||||
@@ -54,7 +54,7 @@ abstract final class AppTheme {
|
||||
outline: AppColors.border,
|
||||
outlineVariant: AppColors.border,
|
||||
surfaceTint: AppColors.transparent,
|
||||
inversePrimary: AppColors.bluePressed,
|
||||
inversePrimary: AppColors.brandRedPressed,
|
||||
error: AppColors.error,
|
||||
onError: AppColors.onPrimary,
|
||||
);
|
||||
@@ -66,16 +66,16 @@ abstract final class AppTheme {
|
||||
canvasColor: AppColors.ink,
|
||||
fontFamily: 'PlusJakartaSans',
|
||||
progressIndicatorTheme: const ProgressIndicatorThemeData(
|
||||
color: AppColors.blue,
|
||||
color: AppColors.brandRed,
|
||||
),
|
||||
sliderTheme: const SliderThemeData(
|
||||
activeTrackColor: AppColors.blue,
|
||||
activeTrackColor: AppColors.brandRed,
|
||||
inactiveTrackColor: AppColors.border,
|
||||
thumbColor: AppColors.onPrimary,
|
||||
),
|
||||
tabBarTheme: const TabBarThemeData(
|
||||
labelColor: AppColors.blue,
|
||||
indicatorColor: AppColors.blue,
|
||||
labelColor: AppColors.brandRed,
|
||||
indicatorColor: AppColors.brandRed,
|
||||
unselectedLabelColor: AppColors.muted,
|
||||
),
|
||||
textButtonTheme: TextButtonThemeData(
|
||||
@@ -138,12 +138,12 @@ abstract final class AppTheme {
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: _inputRadius,
|
||||
borderSide: const BorderSide(color: AppColors.blue),
|
||||
borderSide: const BorderSide(color: AppColors.brandRed),
|
||||
),
|
||||
),
|
||||
chipTheme: ChipThemeData(
|
||||
backgroundColor: AppColors.raised,
|
||||
selectedColor: AppColors.blue.withValues(alpha: 0.22),
|
||||
selectedColor: AppColors.brandRed.withValues(alpha: 0.22),
|
||||
labelStyle: const TextStyle(color: AppColors.onSurface),
|
||||
secondaryLabelStyle: const TextStyle(color: AppColors.muted),
|
||||
side: const BorderSide(color: AppColors.border),
|
||||
@@ -216,7 +216,7 @@ abstract final class AppTheme {
|
||||
),
|
||||
trackColor: WidgetStateProperty.resolveWith(
|
||||
(states) =>
|
||||
states.contains(WidgetState.selected) ? AppColors.blue : null,
|
||||
states.contains(WidgetState.selected) ? AppColors.brandRed : null,
|
||||
),
|
||||
),
|
||||
snackBarTheme: const SnackBarThemeData(
|
||||
@@ -273,8 +273,8 @@ abstract final class AppTheme {
|
||||
if (states.contains(WidgetState.pressed) ||
|
||||
states.contains(WidgetState.hovered) ||
|
||||
states.contains(WidgetState.focused)) {
|
||||
return AppColors.bluePressed;
|
||||
return AppColors.brandRedPressed;
|
||||
}
|
||||
return AppColors.blue;
|
||||
return AppColors.brandRed;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../theme/app_colors.dart';
|
||||
import '../theme/app_theme.dart';
|
||||
import 'subpage_header.dart';
|
||||
|
||||
/// 二级页面通用骨架:返回栏 + 标题/副标题 + 可滚动内容,无底部导航。
|
||||
@@ -29,7 +28,19 @@ class PlainPageScaffold extends StatelessWidget {
|
||||
key: pageKey,
|
||||
backgroundColor: AppColors.ink,
|
||||
body: DecoratedBox(
|
||||
decoration: const BoxDecoration(gradient: AppTheme.pageGradient),
|
||||
// 与首页各 tab 同族:纯黑底 + 顶部暗红光晕。
|
||||
decoration: const BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
AppColors.followingGlow,
|
||||
AppColors.followingGlowMid,
|
||||
AppColors.appBackground,
|
||||
],
|
||||
stops: [0, 0.14, 0.3],
|
||||
),
|
||||
),
|
||||
child: SafeArea(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
||||
@@ -74,9 +74,13 @@ class RemoteImage extends StatelessWidget {
|
||||
: null);
|
||||
final cacheWidth =
|
||||
decodeWidth ?? resolveImageDecodePixels(layoutWidth, pixelRatio);
|
||||
final cacheHeight =
|
||||
decodeHeight ??
|
||||
(inferredHeight == null
|
||||
// cover/contain 本身会保持宽高比,此时若同时强制 cacheWidth 和
|
||||
// cacheHeight,解码会把竖版图强行拉成横版像素。只在显式指定了
|
||||
// decodeHeight、或 fit 不保持宽高比时才限定解码高度。
|
||||
final keepsAspectRatio =
|
||||
fit == BoxFit.cover || fit == BoxFit.contain;
|
||||
final cacheHeight = decodeHeight ??
|
||||
(keepsAspectRatio || inferredHeight == null
|
||||
? null
|
||||
: resolveImageDecodePixels(inferredHeight, pixelRatio));
|
||||
return Image.network(
|
||||
|
||||
@@ -8,7 +8,7 @@ const double _height = 52;
|
||||
const double _heightWithSubtitle = 64;
|
||||
const double _horizontal = 14;
|
||||
const double _backSize = 40;
|
||||
const double _backGap = 12;
|
||||
const double _backGap = 6;
|
||||
const double _titleFontSize = 18;
|
||||
const double _subtitleFontSize = 12;
|
||||
const double _actionGap = 8;
|
||||
@@ -163,7 +163,7 @@ class AppSubpageHeader extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
color: foreground,
|
||||
fontSize: _titleFontSize,
|
||||
fontWeight: FontWeight.w800,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
if (subtitle != null) ...[
|
||||
|
||||
Reference in new issue
Block a user