From 37e35f4b4767839b430d70c3eb04d3d77565fb7a Mon Sep 17 00:00:00 2001 From: Zhou Weidong <502333560@qq.com> Date: Thu, 22 Oct 2026 22:01:36 +0800 Subject: [PATCH] =?UTF-8?q?style:=20=E7=BB=9F=E4=B8=80=E5=85=A8=E7=AB=99?= =?UTF-8?q?=E6=B7=B1=E8=89=B2=E8=A7=86=E8=A7=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/plans/PROGRESS.md | 7 ++++ lib/core/theme/app_colors.dart | 32 ++++++++--------- lib/core/theme/app_theme.dart | 24 +++++++------ lib/core/widgets/plain_page_scaffold.dart | 26 ++++++++------ lib/core/widgets/subpage_header.dart | 36 ++++++++----------- lib/pages/auth/auth_widgets.dart | 2 +- lib/pages/downloads/downloads_page.dart | 7 ++-- .../widgets/drama_detail_header.dart | 9 ++--- .../widgets/drama_detail_sections.dart | 4 ++- .../widgets/drama_episode_states.dart | 4 ++- lib/pages/favorites/favorites_page.dart | 5 +-- lib/pages/filter/filter_page.dart | 1 + lib/pages/new_releases/new_releases_page.dart | 17 ++------- lib/pages/notices/notices_page.dart | 5 ++- lib/pages/ranking/ranking_page.dart | 8 ++--- lib/pages/reserve/reserve_page.dart | 4 ++- lib/pages/settings/settings_page.dart | 6 +++- lib/pages/store/store_page.dart | 4 +-- lib/pages/wallet/wallet_page.dart | 17 ++------- .../widgets/watch_record_card.dart | 8 ++--- test/core/subpage_header_test.dart | 10 +++--- test/drama_detail/drama_detail_view_test.dart | 3 +- test/theme/app_theme_test.dart | 23 ++++++++---- test/theme/dark_theme_smoke_test.dart | 2 +- 24 files changed, 134 insertions(+), 130 deletions(-) diff --git a/docs/plans/PROGRESS.md b/docs/plans/PROGRESS.md index e95abe9..4d8d39f 100644 --- a/docs/plans/PROGRESS.md +++ b/docs/plans/PROGRESS.md @@ -1275,3 +1275,10 @@ $ flutter test - 仅为推荐页「剧单」子页增加暖黑三段渐变和品牌橙径向光晕,推荐视频与全部短剧背景不变。 - 渐变复用「我的」页色值,光晕使用 `#26FF6B2C`;分区与卡片样式保持原样;`flutter analyze`:No issues found。 + +## 2026-10-22 全站深色视觉统一 + +- 全局 token 改为纯黑页面、`#16161A` 卡片、`#1C1C1E` 描边/分割线与 B0/8E 文本层级,旧深蓝页面渐变替换为暖黑渐变。 +- 普通二级页标题栏改为透明、白色标题与返回图标;统一卡片 12 圆角、1px 描边和无阴影策略。 +- 覆盖新剧、筛选、榜单、预约、收藏、观看历史、下载、设置、钱包、VIP、通知、详情、登录、关于;播放器沉浸区保持纯黑。 +- `flutter analyze`:No issues found。 diff --git a/lib/core/theme/app_colors.dart b/lib/core/theme/app_colors.dart index 87d9b92..41966ee 100644 --- a/lib/core/theme/app_colors.dart +++ b/lib/core/theme/app_colors.dart @@ -35,8 +35,8 @@ abstract final class AppColors { /// 主操作按下态。 static const bluePressed = Color(0xFFE55A1F); - /// 链接与次要高亮(禁止大面积铺色)。 - static const blueSoft = Color(0xFF22D3EE); + /// 链接与次要高亮:统一改用中性浅灰,避免旧青色残留。 + static const blueSoft = Color(0xFFB0B0B0); static const secondary = blueSoft; static const lavender = blueSoft; @@ -67,13 +67,13 @@ abstract final class AppColors { static const onPrimary = Color(0xFFFFFFFF); /// 页面背景。 - static const ink = Color(0xFF0B1020); + static const ink = Color(0xFF000000); /// 首页/追剧/我的统一的纯黑内容背景。 static const appBackground = Color(0xFF000000); /// 中性深灰卡片与控件表面。 - static const contentCard = Color(0xFF171717); + static const contentCard = Color(0xFF16161A); static const contentSurface = Color(0xFF1C1C1E); static const contentChip = Color(0xFF2C2C2E); static const contentBorder = Color(0x1AFFFFFF); @@ -105,16 +105,16 @@ abstract final class AppColors { /// 次级文字与列表 chevron。 static const textPrimary = Color(0xFFFFFFFF); - static const textSecondary = Color(0xFF8E8E93); - static const textTertiary = Color(0xFF9E9E9E); + static const textSecondary = Color(0xFFB0B0B0); + static const textTertiary = Color(0xFF8E8E93); static const textTabInactive = Color(0xFFB0B0B0); static const textFilterIcon = Color(0xFF7A7A7E); /// 原生开屏与冷启动过渡底色。 static const splashInk = ink; - /// 顶部与页面底同色,靠容器层次区分。 - static const surfaceTop = ink; + /// 页面顶部暖黑色,渐变底部仍收口到纯黑。 + static const surfaceTop = mineGradientTop; /// 底部导航底色。 static const bar = ink; @@ -127,13 +127,13 @@ abstract final class AppColors { static const cardShadow = Color(0x00000000); /// 卡片与列表容器。 - static const card = Color(0xFF151B2E); + static const card = Color(0xFF16161A); /// 次要卡片表面。 - static const cardAlt = card; + static const cardAlt = Color(0xFF101010); /// 浮层、弹窗、输入与嵌套区域。 - static const raised = Color(0xFF1C2436); + static const raised = Color(0xFF1C1C1E); static const quick = raised; static const input = raised; @@ -156,13 +156,13 @@ abstract final class AppColors { /// 橙色强调文案。 static const accent = blue; - /// 分割线 rgba(255,255,255,0.06)。 - static const border = Color(0x0FFFFFFF); + /// 统一卡片描边、分割线与输入框边框。 + static const border = Color(0xFF1C1C1E); /// 玻璃面板描边。 static const glassBorder = Color(0x33FFFFFF); - static const glassSurfaceStart = Color(0xEB1C2436); - static const glassSurfaceEnd = Color(0xD1151B2E); + static const glassSurfaceStart = Color(0xEB16161A); + static const glassSurfaceEnd = Color(0xD1101010); /// 角标底与文字。 static const badgePink = Color(0x33FF6A8A); @@ -194,7 +194,7 @@ abstract final class AppColors { static const inactiveTrack = Color(0x24FFFFFF); /// 横幅/封面底部渐变。 - static const bannerScrimMid = Color(0x8A0B1020); + static const bannerScrimMid = Color(0x8A1A0C07); static const bannerScrimEnd = Color(0xE6000000); /// 票券虚线等主色描边。 diff --git a/lib/core/theme/app_theme.dart b/lib/core/theme/app_theme.dart index 8cc1e5c..0f1789a 100644 --- a/lib/core/theme/app_theme.dart +++ b/lib/core/theme/app_theme.dart @@ -8,12 +8,16 @@ import 'app_dimens.dart'; /// 深色视觉主题(默认且唯一)。 abstract final class AppTheme { - /// 页面背景:深色扁平,靠容器层次区分。 + /// 页面背景:顶部暖黑、底部纯黑,避免旧深蓝渐变。 static const LinearGradient pageGradient = LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, - colors: [AppColors.surfaceTop, AppColors.ink], - stops: [0, 0.24], + colors: [ + AppColors.mineGradientTop, + AppColors.mineGradientMiddle, + AppColors.mineGradientBottom, + ], + stops: [0, 0.4, 0.75], ); /// 卡片阴影关闭,改用底色与分割线。 @@ -76,7 +80,7 @@ abstract final class AppTheme { ), textButtonTheme: TextButtonThemeData( style: TextButton.styleFrom( - foregroundColor: AppColors.secondary, + foregroundColor: AppColors.primary, shape: RoundedRectangleBorder(borderRadius: _buttonRadius), ), ), @@ -107,12 +111,12 @@ abstract final class AppTheme { ), outlinedButtonTheme: OutlinedButtonThemeData( style: ButtonStyle( - foregroundColor: const WidgetStatePropertyAll(AppColors.blue), + foregroundColor: const WidgetStatePropertyAll(AppColors.textPrimary), minimumSize: const WidgetStatePropertyAll( Size(0, AppDimens.buttonHeight), ), side: const WidgetStatePropertyAll( - BorderSide(color: AppColors.border), + BorderSide(color: AppColors.mineOutline), ), shape: WidgetStatePropertyAll( RoundedRectangleBorder(borderRadius: _buttonRadius), @@ -148,20 +152,20 @@ abstract final class AppTheme { ), ), appBarTheme: const AppBarTheme( - backgroundColor: AppColors.card, - foregroundColor: AppColors.onSurface, + backgroundColor: AppColors.transparent, + foregroundColor: AppColors.textPrimary, elevation: 0, scrolledUnderElevation: 0, surfaceTintColor: AppColors.transparent, systemOverlayStyle: SystemUiOverlayStyle.light, titleTextStyle: TextStyle( - color: AppColors.onSurface, + color: AppColors.textPrimary, fontFamily: 'Outfit', fontSize: AppDimens.pageTitle, fontWeight: FontWeight.w800, ), ), - iconTheme: const IconThemeData(color: AppColors.onSurface), + iconTheme: const IconThemeData(color: AppColors.textPrimary), dividerTheme: const DividerThemeData( color: AppColors.border, thickness: 1, diff --git a/lib/core/widgets/plain_page_scaffold.dart b/lib/core/widgets/plain_page_scaffold.dart index 8e5c07f..29c83e4 100644 --- a/lib/core/widgets/plain_page_scaffold.dart +++ b/lib/core/widgets/plain_page_scaffold.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import '../theme/app_colors.dart'; +import '../theme/app_theme.dart'; import 'subpage_header.dart'; /// 二级页面通用骨架:返回栏 + 标题/副标题 + 可滚动内容,无底部导航。 @@ -27,17 +28,20 @@ class PlainPageScaffold extends StatelessWidget { return Scaffold( key: pageKey, backgroundColor: AppColors.ink, - body: SafeArea( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - AppSubpageHeader( - title: title, - subtitle: subtitle, - backKey: backKey, - ), - Expanded(child: child), - ], + body: DecoratedBox( + decoration: const BoxDecoration(gradient: AppTheme.pageGradient), + child: SafeArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AppSubpageHeader( + title: title, + subtitle: subtitle, + backKey: backKey, + ), + Expanded(child: child), + ], + ), ), ), ); diff --git a/lib/core/widgets/subpage_header.dart b/lib/core/widgets/subpage_header.dart index 0c57432..1f19d0d 100644 --- a/lib/core/widgets/subpage_header.dart +++ b/lib/core/widgets/subpage_header.dart @@ -14,9 +14,7 @@ const double _subtitleFontSize = 12; const double _actionGap = 8; const double _iconSize = 22; const double _iconWeight = 600; -const double _borderWidth = 1; const double _shadowBlur = 8; -const Offset _lightShadowOffset = Offset(0, 2); /// 二级页面统一圆形操作按钮,返回、分享和更多共用同一尺寸与表面样式。 class AppSubpageCircleButton extends StatelessWidget { @@ -47,24 +45,18 @@ class AppSubpageCircleButton extends StatelessWidget { key: const Key('subpage-back-shadow'), decoration: BoxDecoration( shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - color: dark ? AppColors.shadowSoft : AppColors.shadowSubtle, - blurRadius: _shadowBlur, - offset: dark ? Offset.zero : _lightShadowOffset, - ), - ], + boxShadow: dark + ? const [ + BoxShadow( + color: AppColors.shadowSoft, + blurRadius: _shadowBlur, + ), + ] + : const [], ), child: Material( - color: dark ? AppColors.headerScrim : AppColors.card, - shape: CircleBorder( - side: dark - ? BorderSide.none - : const BorderSide( - color: AppColors.border, - width: _borderWidth, - ), - ), + color: dark ? AppColors.headerScrim : AppColors.transparent, + shape: const CircleBorder(), clipBehavior: Clip.antiAlias, child: InkWell( customBorder: const CircleBorder(), @@ -72,7 +64,7 @@ class AppSubpageCircleButton extends StatelessWidget { child: Center( child: Icon( icon, - color: AppColors.onSurface, + color: dark ? AppColors.onSurface : AppColors.textPrimary, size: _iconSize, weight: _iconWeight, ), @@ -85,7 +77,7 @@ class AppSubpageCircleButton extends StatelessWidget { } } -/// 二级页面统一返回按钮,浅色页使用白底描边,深色页使用半透明黑底。 +/// 二级页面统一返回按钮,普通页透明,沉浸页使用半透明黑底。 class AppSubpageBackButton extends StatelessWidget { const AppSubpageBackButton({ super.key, @@ -133,8 +125,8 @@ class AppSubpageHeader extends StatelessWidget { @override Widget build(BuildContext context) { - final foreground = AppColors.onSurface; - final secondary = AppColors.muted; + final foreground = AppColors.textPrimary; + final secondary = AppColors.textSecondary; return SizedBox( key: const Key('subpage-header'), height: subtitle == null ? _height : _heightWithSubtitle, diff --git a/lib/pages/auth/auth_widgets.dart b/lib/pages/auth/auth_widgets.dart index 55b160e..aaf377a 100644 --- a/lib/pages/auth/auth_widgets.dart +++ b/lib/pages/auth/auth_widgets.dart @@ -76,7 +76,7 @@ class _AuthCard extends StatelessWidget { decoration: BoxDecoration( color: AppColors.card, borderRadius: BorderRadius.circular(_cardRadius), - boxShadow: const [AppTheme.cardShadow], + border: Border.all(color: AppColors.border), ), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, diff --git a/lib/pages/downloads/downloads_page.dart b/lib/pages/downloads/downloads_page.dart index 4be91fc..e6ada06 100644 --- a/lib/pages/downloads/downloads_page.dart +++ b/lib/pages/downloads/downloads_page.dart @@ -227,8 +227,8 @@ class _PolicyPanel extends StatelessWidget { padding: const EdgeInsets.fromLTRB(16, 16, 16, 12), decoration: BoxDecoration( color: AppColors.card, - borderRadius: BorderRadius.circular(AppDimens.innerRadius), - border: Border.all(color: AppColors.outlineVariantDark), + borderRadius: BorderRadius.circular(AppDimens.cardRadius), + border: Border.all(color: AppColors.border), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -362,7 +362,8 @@ class _LicenseTile extends StatelessWidget { padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: AppColors.card, - borderRadius: BorderRadius.circular(AppDimens.innerRadius), + borderRadius: BorderRadius.circular(AppDimens.cardRadius), + border: Border.all(color: AppColors.border), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/pages/drama_detail/widgets/drama_detail_header.dart b/lib/pages/drama_detail/widgets/drama_detail_header.dart index d1da929..5c27728 100644 --- a/lib/pages/drama_detail/widgets/drama_detail_header.dart +++ b/lib/pages/drama_detail/widgets/drama_detail_header.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import '../../../core/data/models/drama.dart'; import '../../../core/formatting/localized_content.dart'; import '../../../core/theme/app_colors.dart'; +import '../../../core/theme/app_theme.dart'; import '../../../core/widgets/remote_image.dart'; import '../../../core/widgets/subpage_header.dart'; import '../../../l10n/app_localizations.dart'; @@ -53,13 +54,7 @@ class DramaDetailHeader extends StatelessWidget { Widget build(BuildContext context) { return Container( key: const Key('detail-hero'), - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [AppColors.surfaceTop, AppColors.ink], - ), - ), + decoration: const BoxDecoration(gradient: AppTheme.pageGradient), child: SafeArea( bottom: false, child: Padding( diff --git a/lib/pages/drama_detail/widgets/drama_detail_sections.dart b/lib/pages/drama_detail/widgets/drama_detail_sections.dart index 1db22b8..cd79043 100644 --- a/lib/pages/drama_detail/widgets/drama_detail_sections.dart +++ b/lib/pages/drama_detail/widgets/drama_detail_sections.dart @@ -5,12 +5,13 @@ import 'package:flutter/material.dart'; import '../../../core/data/models/drama.dart'; import '../../../core/formatting/count_format.dart'; import '../../../core/theme/app_colors.dart'; +import '../../../core/theme/app_dimens.dart'; import '../../../l10n/app_localizations.dart'; const double _horizontal = 14; const double _sectionTop = 16; const double _statsVertical = 12; -const double _statsRadius = 14; +const double _statsRadius = AppDimens.cardRadius; const double _dividerHeight = 28; const int _synopsisLines = 3; const int _gridColumns = 6; @@ -63,6 +64,7 @@ class DramaStatsCard extends StatelessWidget { decoration: BoxDecoration( color: AppColors.card, borderRadius: BorderRadius.circular(_statsRadius), + border: Border.all(color: AppColors.border), ), child: Row( children: [ diff --git a/lib/pages/drama_detail/widgets/drama_episode_states.dart b/lib/pages/drama_detail/widgets/drama_episode_states.dart index de7787d..39db405 100644 --- a/lib/pages/drama_detail/widgets/drama_episode_states.dart +++ b/lib/pages/drama_detail/widgets/drama_episode_states.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import '../../../core/formatting/error_text.dart'; import '../../../core/theme/app_colors.dart'; +import '../../../core/theme/app_dimens.dart'; import '../../../l10n/app_localizations.dart'; const int _skeletonCount = 6; @@ -138,7 +139,8 @@ class DramaEpisodesLoadError extends StatelessWidget { padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: AppColors.card, - borderRadius: BorderRadius.circular(14), + borderRadius: BorderRadius.circular(AppDimens.cardRadius), + border: Border.all(color: AppColors.border), ), child: Column( children: [ diff --git a/lib/pages/favorites/favorites_page.dart b/lib/pages/favorites/favorites_page.dart index 5452ec1..e751b5b 100644 --- a/lib/pages/favorites/favorites_page.dart +++ b/lib/pages/favorites/favorites_page.dart @@ -12,6 +12,7 @@ import '../../core/formatting/count_format.dart'; import '../../core/formatting/error_text.dart'; import '../../core/platform/haptics.dart'; import '../../core/theme/app_colors.dart'; +import '../../core/theme/app_dimens.dart'; import '../../core/theme/app_theme.dart'; import '../../core/widgets/app_pull_to_refresh.dart'; import '../../core/widgets/auth_gate.dart'; @@ -24,7 +25,7 @@ import '../player/open_player.dart'; import 'favorites_binding.dart'; const double _pageHorizontal = 14; -const double _cardRadius = 14; +const double _cardRadius = AppDimens.cardRadius; const double _cardPadding = 10; const double _coverWidth = 80; const double _coverHeight = 106; @@ -273,7 +274,7 @@ class _FavoriteCard extends StatelessWidget { decoration: BoxDecoration( color: AppColors.card, borderRadius: BorderRadius.circular(_cardRadius), - boxShadow: const [AppTheme.cardShadow], + border: Border.all(color: AppColors.border), ), child: Material( color: AppColors.transparent, diff --git a/lib/pages/filter/filter_page.dart b/lib/pages/filter/filter_page.dart index 43dc6dc..d1f62d0 100644 --- a/lib/pages/filter/filter_page.dart +++ b/lib/pages/filter/filter_page.dart @@ -255,6 +255,7 @@ class _FilterPageState extends State { decoration: BoxDecoration( color: AppColors.card, borderRadius: BorderRadius.circular(12), + border: Border.all(color: AppColors.border), ), child: Row( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/pages/new_releases/new_releases_page.dart b/lib/pages/new_releases/new_releases_page.dart index 12351e3..3de4c34 100644 --- a/lib/pages/new_releases/new_releases_page.dart +++ b/lib/pages/new_releases/new_releases_page.dart @@ -10,6 +10,7 @@ import '../../core/data/models/drama.dart'; import '../../core/data/services/catalog_controller.dart'; import '../../core/formatting/count_format.dart'; import '../../core/theme/app_colors.dart'; +import '../../core/theme/app_theme.dart'; import '../../core/widgets/app_pull_to_refresh.dart'; import '../../core/widgets/paged_local_list.dart'; import '../../core/widgets/remote_image.dart'; @@ -107,13 +108,7 @@ class _NewReleasesPageState extends State { key: const Key('new-releases-page'), backgroundColor: AppColors.ink, body: DecoratedBox( - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [AppColors.surfaceTop, AppColors.ink], - ), - ), + decoration: const BoxDecoration(gradient: AppTheme.pageGradient), child: SafeArea( child: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -407,13 +402,7 @@ class _NewReleasesPageState extends State { decoration: BoxDecoration( color: AppColors.card, borderRadius: BorderRadius.circular(_cardRadius), - boxShadow: const [ - BoxShadow( - color: AppColors.cardShadow, - blurRadius: 12, - offset: Offset(0, 4), - ), - ], + border: Border.all(color: AppColors.border), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/pages/notices/notices_page.dart b/lib/pages/notices/notices_page.dart index 4ed3619..f9df1fd 100644 --- a/lib/pages/notices/notices_page.dart +++ b/lib/pages/notices/notices_page.dart @@ -213,7 +213,10 @@ class _NoticeTile extends StatelessWidget { return Material( key: ValueKey('notice-item-${notice.id}'), color: AppColors.card, - borderRadius: BorderRadius.circular(AppDimens.innerRadius), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(AppDimens.cardRadius), + side: const BorderSide(color: AppColors.border), + ), clipBehavior: Clip.antiAlias, child: InkWell( onTap: onTap, diff --git a/lib/pages/ranking/ranking_page.dart b/lib/pages/ranking/ranking_page.dart index 615e9b3..749001a 100644 --- a/lib/pages/ranking/ranking_page.dart +++ b/lib/pages/ranking/ranking_page.dart @@ -9,7 +9,7 @@ import '../../core/data/models/drama.dart'; import '../../core/data/services/catalog_controller.dart'; import '../../core/formatting/count_format.dart'; import '../../core/theme/app_colors.dart'; -import '../../core/theme/app_theme.dart'; +import '../../core/theme/app_dimens.dart'; import '../../core/widgets/app_pull_to_refresh.dart'; import '../../core/widgets/empty_state.dart'; import '../../core/widgets/paged_local_list.dart'; @@ -341,12 +341,12 @@ class _RankingRow extends StatelessWidget { return Container( decoration: BoxDecoration( color: AppColors.card, - borderRadius: BorderRadius.circular(14), - boxShadow: const [AppTheme.cardShadow], + borderRadius: BorderRadius.circular(AppDimens.cardRadius), + border: Border.all(color: AppColors.border), ), child: Material( color: AppColors.transparent, - borderRadius: BorderRadius.circular(14), + borderRadius: BorderRadius.circular(AppDimens.cardRadius), clipBehavior: Clip.antiAlias, child: InkWell( key: Key('ranking-row-$index'), diff --git a/lib/pages/reserve/reserve_page.dart b/lib/pages/reserve/reserve_page.dart index b6bd7c7..d5e1385 100644 --- a/lib/pages/reserve/reserve_page.dart +++ b/lib/pages/reserve/reserve_page.dart @@ -5,12 +5,13 @@ import 'package:provider/provider.dart'; import '../../core/data/services/catalog_controller.dart'; import '../../core/theme/app_colors.dart'; +import '../../core/theme/app_dimens.dart'; import '../../core/widgets/app_pull_to_refresh.dart'; import '../../core/widgets/subpage_header.dart'; import '../../l10n/app_localizations.dart'; import '../new_releases/new_releases_page.dart'; -const double _ticketRadius = 20; +const double _ticketRadius = AppDimens.cardRadius; const double _notchSize = 24; const Color _ticketDash = AppColors.primaryBorder; @@ -163,6 +164,7 @@ class _ReservePageState extends State { decoration: BoxDecoration( color: AppColors.card, borderRadius: BorderRadius.circular(_ticketRadius), + border: Border.all(color: AppColors.border), ), child: Column( children: [ diff --git a/lib/pages/settings/settings_page.dart b/lib/pages/settings/settings_page.dart index 180ca52..ed5b20b 100644 --- a/lib/pages/settings/settings_page.dart +++ b/lib/pages/settings/settings_page.dart @@ -7,6 +7,7 @@ import 'package:provider/provider.dart'; import '../../core/data/services/auth_controller.dart'; import '../../core/theme/app_colors.dart'; +import '../../core/theme/app_dimens.dart'; import '../../core/theme/app_theme.dart'; import '../../core/widgets/auth_gate.dart'; import '../../core/widgets/plain_page_scaffold.dart'; @@ -47,7 +48,10 @@ class SettingsPage extends StatelessWidget { Widget _noticesTile(BuildContext context, AppLocalizations l10n) { return Material( color: AppColors.card, - borderRadius: BorderRadius.circular(14), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(AppDimens.cardRadius), + side: const BorderSide(color: AppColors.border), + ), clipBehavior: Clip.antiAlias, child: ListTile( key: const Key('settings-notices'), diff --git a/lib/pages/store/store_page.dart b/lib/pages/store/store_page.dart index 63bb10a..3c00467 100644 --- a/lib/pages/store/store_page.dart +++ b/lib/pages/store/store_page.dart @@ -151,8 +151,8 @@ class _ProductTile extends StatelessWidget { padding: const EdgeInsets.fromLTRB(14, 14, 12, 14), decoration: BoxDecoration( color: AppColors.card, - borderRadius: BorderRadius.circular(16), - border: Border.all(color: AppColors.gold.withValues(alpha: 0.26)), + borderRadius: BorderRadius.circular(AppDimens.cardRadius), + border: Border.all(color: AppColors.border), ), child: Row( children: [ diff --git a/lib/pages/wallet/wallet_page.dart b/lib/pages/wallet/wallet_page.dart index 86b9827..359d7d1 100644 --- a/lib/pages/wallet/wallet_page.dart +++ b/lib/pages/wallet/wallet_page.dart @@ -183,20 +183,9 @@ class _BalanceHero extends StatelessWidget { key: const Key('wallet-balance-card'), padding: const EdgeInsets.fromLTRB(20, 22, 20, 20), decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - gradient: const LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [AppColors.goldCard, AppColors.card], - ), - border: Border.all(color: AppColors.gold.withValues(alpha: 0.35)), - boxShadow: [ - BoxShadow( - color: AppColors.gold.withValues(alpha: 0.08), - blurRadius: 28, - offset: const Offset(0, 14), - ), - ], + color: AppColors.card, + borderRadius: BorderRadius.circular(AppDimens.cardRadius), + border: Border.all(color: AppColors.border), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/pages/watch_records/widgets/watch_record_card.dart b/lib/pages/watch_records/widgets/watch_record_card.dart index edb59ef..4fa1f0b 100644 --- a/lib/pages/watch_records/widgets/watch_record_card.dart +++ b/lib/pages/watch_records/widgets/watch_record_card.dart @@ -5,11 +5,11 @@ import 'package:flutter/material.dart'; import '../../../core/data/models/watch_record.dart'; import '../../../core/formatting/localized_date_time.dart'; import '../../../core/theme/app_colors.dart'; -import '../../../core/theme/app_theme.dart'; +import '../../../core/theme/app_dimens.dart'; import '../../../core/widgets/remote_image.dart'; import '../../../l10n/app_localizations.dart'; -const double _cardRadius = 14; +const double _cardRadius = AppDimens.cardRadius; const double _cardPadding = 10; const double _coverWidth = 72; const double _coverHeight = 96; @@ -187,7 +187,7 @@ class WatchRecordCard extends StatelessWidget { BoxDecoration _cardDecoration() => BoxDecoration( color: AppColors.card, borderRadius: BorderRadius.circular(_cardRadius), - boxShadow: const [AppTheme.cardShadow], + border: Border.all(color: AppColors.border), ); Widget _removeButton(String tooltip) { @@ -227,7 +227,7 @@ class _FailedRecordTile extends StatelessWidget { decoration: BoxDecoration( color: AppColors.card, borderRadius: BorderRadius.circular(_cardRadius), - boxShadow: const [AppTheme.cardShadow], + border: Border.all(color: AppColors.border), ), child: Container( key: ValueKey('watch-record-failed-${record.dramaId}'), diff --git a/test/core/subpage_header_test.dart b/test/core/subpage_header_test.dart index cf8d3ea..16b0024 100644 --- a/test/core/subpage_header_test.dart +++ b/test/core/subpage_header_test.dart @@ -28,7 +28,7 @@ void main() { final title = tester.widget(find.byKey(const Key('subpage-title'))); expect(title.style?.fontSize, 18); expect(title.style?.fontWeight, FontWeight.w800); - expect(title.style?.color, AppColors.onSurface); + expect(title.style?.color, AppColors.textPrimary); final back = tester.getRect(find.byKey(const Key('sample-back'))); final titleRect = tester.getRect(find.byKey(const Key('subpage-title'))); expect(titleRect.left - back.right, closeTo(12, 0.5)); @@ -38,8 +38,8 @@ void main() { matching: find.byType(Material), ), ); - expect(surface.color, AppColors.card); - expect((surface.shape! as CircleBorder).side.color, AppColors.border); + expect(surface.color, AppColors.transparent); + expect((surface.shape! as CircleBorder).side, BorderSide.none); final shadow = tester .widget( @@ -47,9 +47,7 @@ void main() { ) .decoration as BoxDecoration; - expect(shadow.boxShadow!.single.color, AppColors.shadowSubtle); - expect(shadow.boxShadow!.single.blurRadius, 8); - expect(shadow.boxShadow!.single.offset, const Offset(0, 2)); + expect(shadow.boxShadow, isEmpty); }); testWidgets('should_use_64_height_when_subtitle_exists', (tester) async { diff --git a/test/drama_detail/drama_detail_view_test.dart b/test/drama_detail/drama_detail_view_test.dart index 0df97ea..30fb3a1 100644 --- a/test/drama_detail/drama_detail_view_test.dart +++ b/test/drama_detail/drama_detail_view_test.dart @@ -94,7 +94,8 @@ void main() { ); final statsDecoration = stats.decoration! as BoxDecoration; expect(statsDecoration.color, AppColors.card); - expect(statsDecoration.borderRadius, BorderRadius.circular(14)); + expect(statsDecoration.borderRadius, BorderRadius.circular(12)); + expect((statsDecoration.border! as Border).top.color, AppColors.border); expect(find.byKey(const Key('detail-synopsis-section')), findsOneWidget); expect(find.byKey(const Key('detail-tags')), findsOneWidget); expect(find.byKey(const Key('detail-episodes-section')), findsOneWidget); diff --git a/test/theme/app_theme_test.dart b/test/theme/app_theme_test.dart index 2f94760..442b452 100644 --- a/test/theme/app_theme_test.dart +++ b/test/theme/app_theme_test.dart @@ -20,11 +20,15 @@ void main() { test('should_expose_dark_visual_tokens', () { expect(AppColors.blue, const Color(0xFFFF6B2C)); expect(AppColors.bluePressed, const Color(0xFFE55A1F)); - expect(AppColors.secondary, const Color(0xFF22D3EE)); - expect(AppColors.ink, const Color(0xFF0B1020)); - expect(AppColors.card, const Color(0xFF151B2E)); - expect(AppColors.raised, const Color(0xFF1C2436)); - expect(AppColors.border, const Color(0x0FFFFFFF)); + expect(AppColors.secondary, const Color(0xFFB0B0B0)); + expect(AppColors.ink, const Color(0xFF000000)); + expect(AppColors.card, const Color(0xFF16161A)); + expect(AppColors.cardAlt, const Color(0xFF101010)); + expect(AppColors.raised, const Color(0xFF1C1C1E)); + expect(AppColors.border, const Color(0xFF1C1C1E)); + expect(AppColors.textPrimary, const Color(0xFFFFFFFF)); + expect(AppColors.textSecondary, const Color(0xFFB0B0B0)); + expect(AppColors.textTertiary, const Color(0xFF8E8E93)); expect(AppColors.onSurface, const Color(0xEBFFFFFF)); expect(AppColors.muted, const Color(0xA3FFFFFF)); expect(AppColors.subtle, const Color(0x61FFFFFF)); @@ -59,7 +63,7 @@ void main() { expect(theme.colorScheme.onSurface, AppColors.onSurface); expect(theme.colorScheme.outline, AppColors.border); expect(theme.scaffoldBackgroundColor, AppColors.ink); - expect(theme.appBarTheme.backgroundColor, AppColors.card); + expect(theme.appBarTheme.backgroundColor, AppColors.transparent); expect(theme.appBarTheme.systemOverlayStyle, SystemUiOverlayStyle.light); expect(theme.cardTheme.elevation, 0); expect(theme.dialogTheme.backgroundColor, AppColors.raised); @@ -91,7 +95,12 @@ void main() { }); test('should_expose_flat_page_gradient_without_card_shadow', () { - expect(AppTheme.pageGradient.colors, [AppColors.surfaceTop, AppColors.ink]); + expect(AppTheme.pageGradient.colors, [ + AppColors.mineGradientTop, + AppColors.mineGradientMiddle, + AppColors.mineGradientBottom, + ]); + expect(AppTheme.pageGradient.stops, [0, 0.4, 0.75]); expect(AppTheme.cardShadow.color, AppColors.cardShadow); expect(AppTheme.cardShadow.blurRadius, 0); expect(AppTheme.cardShadow.offset, Offset.zero); diff --git a/test/theme/dark_theme_smoke_test.dart b/test/theme/dark_theme_smoke_test.dart index 2fea453..7ece6f6 100644 --- a/test/theme/dark_theme_smoke_test.dart +++ b/test/theme/dark_theme_smoke_test.dart @@ -65,7 +65,7 @@ void main() { final theme = Theme.of(context); expect(theme.brightness, Brightness.dark); expect(theme.scaffoldBackgroundColor, AppColors.ink); - expect(theme.appBarTheme.backgroundColor, AppColors.card); + expect(theme.appBarTheme.backgroundColor, AppColors.transparent); expect(theme.cardTheme.color, AppColors.card); final card = tester.widget(find.byKey(const Key('dark-smoke-card')));