style: 统一全站深色视觉

This commit is contained in:
Zhou Weidong committed 2026-10-22 22:01:36 +08:00
1 parent 86aa7e0f4f
commit 37e35f4b47
24 files changed
+134 -130

No files matched your search

+7
View File
@@ -1275,3 +1275,10 @@ $ flutter test
- 仅为推荐页「剧单」子页增加暖黑三段渐变和品牌橙径向光晕,推荐视频与全部短剧背景不变。 - 仅为推荐页「剧单」子页增加暖黑三段渐变和品牌橙径向光晕,推荐视频与全部短剧背景不变。
- 渐变复用「我的」页色值,光晕使用 `#26FF6B2C`;分区与卡片样式保持原样;`flutter analyze`:No issues found。 - 渐变复用「我的」页色值,光晕使用 `#26FF6B2C`;分区与卡片样式保持原样;`flutter analyze`:No issues found。
## 2026-10-22 全站深色视觉统一
- 全局 token 改为纯黑页面、`#16161A` 卡片、`#1C1C1E` 描边/分割线与 B0/8E 文本层级,旧深蓝页面渐变替换为暖黑渐变。
- 普通二级页标题栏改为透明、白色标题与返回图标;统一卡片 12 圆角、1px 描边和无阴影策略。
- 覆盖新剧、筛选、榜单、预约、收藏、观看历史、下载、设置、钱包、VIP、通知、详情、登录、关于;播放器沉浸区保持纯黑。
- `flutter analyze`:No issues found。
+16 -16
View File
@@ -35,8 +35,8 @@ abstract final class AppColors {
/// 主操作按下态。 /// 主操作按下态。
static const bluePressed = Color(0xFFE55A1F); static const bluePressed = Color(0xFFE55A1F);
/// 链接与次要高亮(禁止大面积铺色)。 /// 链接与次要高亮:统一改用中性浅灰,避免旧青色残留。
static const blueSoft = Color(0xFF22D3EE); static const blueSoft = Color(0xFFB0B0B0);
static const secondary = blueSoft; static const secondary = blueSoft;
static const lavender = blueSoft; static const lavender = blueSoft;
@@ -67,13 +67,13 @@ abstract final class AppColors {
static const onPrimary = Color(0xFFFFFFFF); static const onPrimary = Color(0xFFFFFFFF);
/// 页面背景。 /// 页面背景。
static const ink = Color(0xFF0B1020); static const ink = Color(0xFF000000);
/// 首页/追剧/我的统一的纯黑内容背景。 /// 首页/追剧/我的统一的纯黑内容背景。
static const appBackground = Color(0xFF000000); static const appBackground = Color(0xFF000000);
/// 中性深灰卡片与控件表面。 /// 中性深灰卡片与控件表面。
static const contentCard = Color(0xFF171717); static const contentCard = Color(0xFF16161A);
static const contentSurface = Color(0xFF1C1C1E); static const contentSurface = Color(0xFF1C1C1E);
static const contentChip = Color(0xFF2C2C2E); static const contentChip = Color(0xFF2C2C2E);
static const contentBorder = Color(0x1AFFFFFF); static const contentBorder = Color(0x1AFFFFFF);
@@ -105,16 +105,16 @@ abstract final class AppColors {
/// 次级文字与列表 chevron。 /// 次级文字与列表 chevron。
static const textPrimary = Color(0xFFFFFFFF); static const textPrimary = Color(0xFFFFFFFF);
static const textSecondary = Color(0xFF8E8E93); static const textSecondary = Color(0xFFB0B0B0);
static const textTertiary = Color(0xFF9E9E9E); static const textTertiary = Color(0xFF8E8E93);
static const textTabInactive = Color(0xFFB0B0B0); static const textTabInactive = Color(0xFFB0B0B0);
static const textFilterIcon = Color(0xFF7A7A7E); static const textFilterIcon = Color(0xFF7A7A7E);
/// 原生开屏与冷启动过渡底色。 /// 原生开屏与冷启动过渡底色。
static const splashInk = ink; static const splashInk = ink;
/// 顶部与页面底同色,靠容器层次区分。 /// 页面顶部暖黑色,渐变底部仍收口到纯黑。
static const surfaceTop = ink; static const surfaceTop = mineGradientTop;
/// 底部导航底色。 /// 底部导航底色。
static const bar = ink; static const bar = ink;
@@ -127,13 +127,13 @@ abstract final class AppColors {
static const cardShadow = Color(0x00000000); 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 quick = raised;
static const input = raised; static const input = raised;
@@ -156,13 +156,13 @@ abstract final class AppColors {
/// 橙色强调文案。 /// 橙色强调文案。
static const accent = blue; 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 glassBorder = Color(0x33FFFFFF);
static const glassSurfaceStart = Color(0xEB1C2436); static const glassSurfaceStart = Color(0xEB16161A);
static const glassSurfaceEnd = Color(0xD1151B2E); static const glassSurfaceEnd = Color(0xD1101010);
/// 角标底与文字。 /// 角标底与文字。
static const badgePink = Color(0x33FF6A8A); static const badgePink = Color(0x33FF6A8A);
@@ -194,7 +194,7 @@ abstract final class AppColors {
static const inactiveTrack = Color(0x24FFFFFF); static const inactiveTrack = Color(0x24FFFFFF);
/// 横幅/封面底部渐变。 /// 横幅/封面底部渐变。
static const bannerScrimMid = Color(0x8A0B1020); static const bannerScrimMid = Color(0x8A1A0C07);
static const bannerScrimEnd = Color(0xE6000000); static const bannerScrimEnd = Color(0xE6000000);
/// 票券虚线等主色描边。 /// 票券虚线等主色描边。
+14 -10
View File
@@ -8,12 +8,16 @@ import 'app_dimens.dart';
/// 深色视觉主题(默认且唯一)。 /// 深色视觉主题(默认且唯一)。
abstract final class AppTheme { abstract final class AppTheme {
/// 页面背景:深色扁平,靠容器层次区分。 /// 页面背景:顶部暖黑、底部纯黑,避免旧深蓝渐变。
static const LinearGradient pageGradient = LinearGradient( static const LinearGradient pageGradient = LinearGradient(
begin: Alignment.topCenter, begin: Alignment.topCenter,
end: Alignment.bottomCenter, end: Alignment.bottomCenter,
colors: [AppColors.surfaceTop, AppColors.ink], colors: [
stops: [0, 0.24], AppColors.mineGradientTop,
AppColors.mineGradientMiddle,
AppColors.mineGradientBottom,
],
stops: [0, 0.4, 0.75],
); );
/// 卡片阴影关闭,改用底色与分割线。 /// 卡片阴影关闭,改用底色与分割线。
@@ -76,7 +80,7 @@ abstract final class AppTheme {
), ),
textButtonTheme: TextButtonThemeData( textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom( style: TextButton.styleFrom(
foregroundColor: AppColors.secondary, foregroundColor: AppColors.primary,
shape: RoundedRectangleBorder(borderRadius: _buttonRadius), shape: RoundedRectangleBorder(borderRadius: _buttonRadius),
), ),
), ),
@@ -107,12 +111,12 @@ abstract final class AppTheme {
), ),
outlinedButtonTheme: OutlinedButtonThemeData( outlinedButtonTheme: OutlinedButtonThemeData(
style: ButtonStyle( style: ButtonStyle(
foregroundColor: const WidgetStatePropertyAll(AppColors.blue), foregroundColor: const WidgetStatePropertyAll(AppColors.textPrimary),
minimumSize: const WidgetStatePropertyAll( minimumSize: const WidgetStatePropertyAll(
Size(0, AppDimens.buttonHeight), Size(0, AppDimens.buttonHeight),
), ),
side: const WidgetStatePropertyAll( side: const WidgetStatePropertyAll(
BorderSide(color: AppColors.border), BorderSide(color: AppColors.mineOutline),
), ),
shape: WidgetStatePropertyAll( shape: WidgetStatePropertyAll(
RoundedRectangleBorder(borderRadius: _buttonRadius), RoundedRectangleBorder(borderRadius: _buttonRadius),
@@ -148,20 +152,20 @@ abstract final class AppTheme {
), ),
), ),
appBarTheme: const AppBarTheme( appBarTheme: const AppBarTheme(
backgroundColor: AppColors.card, backgroundColor: AppColors.transparent,
foregroundColor: AppColors.onSurface, foregroundColor: AppColors.textPrimary,
elevation: 0, elevation: 0,
scrolledUnderElevation: 0, scrolledUnderElevation: 0,
surfaceTintColor: AppColors.transparent, surfaceTintColor: AppColors.transparent,
systemOverlayStyle: SystemUiOverlayStyle.light, systemOverlayStyle: SystemUiOverlayStyle.light,
titleTextStyle: TextStyle( titleTextStyle: TextStyle(
color: AppColors.onSurface, color: AppColors.textPrimary,
fontFamily: 'Outfit', fontFamily: 'Outfit',
fontSize: AppDimens.pageTitle, fontSize: AppDimens.pageTitle,
fontWeight: FontWeight.w800, fontWeight: FontWeight.w800,
), ),
), ),
iconTheme: const IconThemeData(color: AppColors.onSurface), iconTheme: const IconThemeData(color: AppColors.textPrimary),
dividerTheme: const DividerThemeData( dividerTheme: const DividerThemeData(
color: AppColors.border, color: AppColors.border,
thickness: 1, thickness: 1,
+15 -11
View File
@@ -3,6 +3,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../theme/app_colors.dart'; import '../theme/app_colors.dart';
import '../theme/app_theme.dart';
import 'subpage_header.dart'; import 'subpage_header.dart';
/// 二级页面通用骨架:返回栏 + 标题/副标题 + 可滚动内容,无底部导航。 /// 二级页面通用骨架:返回栏 + 标题/副标题 + 可滚动内容,无底部导航。
@@ -27,17 +28,20 @@ class PlainPageScaffold extends StatelessWidget {
return Scaffold( return Scaffold(
key: pageKey, key: pageKey,
backgroundColor: AppColors.ink, backgroundColor: AppColors.ink,
body: SafeArea( body: DecoratedBox(
child: Column( decoration: const BoxDecoration(gradient: AppTheme.pageGradient),
crossAxisAlignment: CrossAxisAlignment.start, child: SafeArea(
children: [ child: Column(
AppSubpageHeader( crossAxisAlignment: CrossAxisAlignment.start,
title: title, children: [
subtitle: subtitle, AppSubpageHeader(
backKey: backKey, title: title,
), subtitle: subtitle,
Expanded(child: child), backKey: backKey,
], ),
Expanded(child: child),
],
),
), ),
), ),
); );
+14 -22
View File
@@ -14,9 +14,7 @@ const double _subtitleFontSize = 12;
const double _actionGap = 8; const double _actionGap = 8;
const double _iconSize = 22; const double _iconSize = 22;
const double _iconWeight = 600; const double _iconWeight = 600;
const double _borderWidth = 1;
const double _shadowBlur = 8; const double _shadowBlur = 8;
const Offset _lightShadowOffset = Offset(0, 2);
/// 二级页面统一圆形操作按钮,返回、分享和更多共用同一尺寸与表面样式。 /// 二级页面统一圆形操作按钮,返回、分享和更多共用同一尺寸与表面样式。
class AppSubpageCircleButton extends StatelessWidget { class AppSubpageCircleButton extends StatelessWidget {
@@ -47,24 +45,18 @@ class AppSubpageCircleButton extends StatelessWidget {
key: const Key('subpage-back-shadow'), key: const Key('subpage-back-shadow'),
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
boxShadow: [ boxShadow: dark
BoxShadow( ? const [
color: dark ? AppColors.shadowSoft : AppColors.shadowSubtle, BoxShadow(
blurRadius: _shadowBlur, color: AppColors.shadowSoft,
offset: dark ? Offset.zero : _lightShadowOffset, blurRadius: _shadowBlur,
), ),
], ]
: const [],
), ),
child: Material( child: Material(
color: dark ? AppColors.headerScrim : AppColors.card, color: dark ? AppColors.headerScrim : AppColors.transparent,
shape: CircleBorder( shape: const CircleBorder(),
side: dark
? BorderSide.none
: const BorderSide(
color: AppColors.border,
width: _borderWidth,
),
),
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
child: InkWell( child: InkWell(
customBorder: const CircleBorder(), customBorder: const CircleBorder(),
@@ -72,7 +64,7 @@ class AppSubpageCircleButton extends StatelessWidget {
child: Center( child: Center(
child: Icon( child: Icon(
icon, icon,
color: AppColors.onSurface, color: dark ? AppColors.onSurface : AppColors.textPrimary,
size: _iconSize, size: _iconSize,
weight: _iconWeight, weight: _iconWeight,
), ),
@@ -85,7 +77,7 @@ class AppSubpageCircleButton extends StatelessWidget {
} }
} }
/// 二级页面统一返回按钮,浅色页使用白底描边,深色页使用半透明黑底。 /// 二级页面统一返回按钮,普通页透明,沉浸页使用半透明黑底。
class AppSubpageBackButton extends StatelessWidget { class AppSubpageBackButton extends StatelessWidget {
const AppSubpageBackButton({ const AppSubpageBackButton({
super.key, super.key,
@@ -133,8 +125,8 @@ class AppSubpageHeader extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final foreground = AppColors.onSurface; final foreground = AppColors.textPrimary;
final secondary = AppColors.muted; final secondary = AppColors.textSecondary;
return SizedBox( return SizedBox(
key: const Key('subpage-header'), key: const Key('subpage-header'),
height: subtitle == null ? _height : _heightWithSubtitle, height: subtitle == null ? _height : _heightWithSubtitle,
+1 -1
View File
@@ -76,7 +76,7 @@ class _AuthCard extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColors.card, color: AppColors.card,
borderRadius: BorderRadius.circular(_cardRadius), borderRadius: BorderRadius.circular(_cardRadius),
boxShadow: const [AppTheme.cardShadow], border: Border.all(color: AppColors.border),
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
+4 -3
View File
@@ -227,8 +227,8 @@ class _PolicyPanel extends StatelessWidget {
padding: const EdgeInsets.fromLTRB(16, 16, 16, 12), padding: const EdgeInsets.fromLTRB(16, 16, 16, 12),
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColors.card, color: AppColors.card,
borderRadius: BorderRadius.circular(AppDimens.innerRadius), borderRadius: BorderRadius.circular(AppDimens.cardRadius),
border: Border.all(color: AppColors.outlineVariantDark), border: Border.all(color: AppColors.border),
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@@ -362,7 +362,8 @@ class _LicenseTile extends StatelessWidget {
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColors.card, color: AppColors.card,
borderRadius: BorderRadius.circular(AppDimens.innerRadius), borderRadius: BorderRadius.circular(AppDimens.cardRadius),
border: Border.all(color: AppColors.border),
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import '../../../core/data/models/drama.dart'; import '../../../core/data/models/drama.dart';
import '../../../core/formatting/localized_content.dart'; import '../../../core/formatting/localized_content.dart';
import '../../../core/theme/app_colors.dart'; import '../../../core/theme/app_colors.dart';
import '../../../core/theme/app_theme.dart';
import '../../../core/widgets/remote_image.dart'; import '../../../core/widgets/remote_image.dart';
import '../../../core/widgets/subpage_header.dart'; import '../../../core/widgets/subpage_header.dart';
import '../../../l10n/app_localizations.dart'; import '../../../l10n/app_localizations.dart';
@@ -53,13 +54,7 @@ class DramaDetailHeader extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
key: const Key('detail-hero'), key: const Key('detail-hero'),
decoration: const BoxDecoration( decoration: const BoxDecoration(gradient: AppTheme.pageGradient),
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [AppColors.surfaceTop, AppColors.ink],
),
),
child: SafeArea( child: SafeArea(
bottom: false, bottom: false,
child: Padding( child: Padding(
@@ -5,12 +5,13 @@ import 'package:flutter/material.dart';
import '../../../core/data/models/drama.dart'; import '../../../core/data/models/drama.dart';
import '../../../core/formatting/count_format.dart'; import '../../../core/formatting/count_format.dart';
import '../../../core/theme/app_colors.dart'; import '../../../core/theme/app_colors.dart';
import '../../../core/theme/app_dimens.dart';
import '../../../l10n/app_localizations.dart'; import '../../../l10n/app_localizations.dart';
const double _horizontal = 14; const double _horizontal = 14;
const double _sectionTop = 16; const double _sectionTop = 16;
const double _statsVertical = 12; const double _statsVertical = 12;
const double _statsRadius = 14; const double _statsRadius = AppDimens.cardRadius;
const double _dividerHeight = 28; const double _dividerHeight = 28;
const int _synopsisLines = 3; const int _synopsisLines = 3;
const int _gridColumns = 6; const int _gridColumns = 6;
@@ -63,6 +64,7 @@ class DramaStatsCard extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColors.card, color: AppColors.card,
borderRadius: BorderRadius.circular(_statsRadius), borderRadius: BorderRadius.circular(_statsRadius),
border: Border.all(color: AppColors.border),
), ),
child: Row( child: Row(
children: [ children: [
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import '../../../core/formatting/error_text.dart'; import '../../../core/formatting/error_text.dart';
import '../../../core/theme/app_colors.dart'; import '../../../core/theme/app_colors.dart';
import '../../../core/theme/app_dimens.dart';
import '../../../l10n/app_localizations.dart'; import '../../../l10n/app_localizations.dart';
const int _skeletonCount = 6; const int _skeletonCount = 6;
@@ -138,7 +139,8 @@ class DramaEpisodesLoadError extends StatelessWidget {
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColors.card, color: AppColors.card,
borderRadius: BorderRadius.circular(14), borderRadius: BorderRadius.circular(AppDimens.cardRadius),
border: Border.all(color: AppColors.border),
), ),
child: Column( child: Column(
children: [ children: [
+3 -2
View File
@@ -12,6 +12,7 @@ import '../../core/formatting/count_format.dart';
import '../../core/formatting/error_text.dart'; import '../../core/formatting/error_text.dart';
import '../../core/platform/haptics.dart'; import '../../core/platform/haptics.dart';
import '../../core/theme/app_colors.dart'; import '../../core/theme/app_colors.dart';
import '../../core/theme/app_dimens.dart';
import '../../core/theme/app_theme.dart'; import '../../core/theme/app_theme.dart';
import '../../core/widgets/app_pull_to_refresh.dart'; import '../../core/widgets/app_pull_to_refresh.dart';
import '../../core/widgets/auth_gate.dart'; import '../../core/widgets/auth_gate.dart';
@@ -24,7 +25,7 @@ import '../player/open_player.dart';
import 'favorites_binding.dart'; import 'favorites_binding.dart';
const double _pageHorizontal = 14; const double _pageHorizontal = 14;
const double _cardRadius = 14; const double _cardRadius = AppDimens.cardRadius;
const double _cardPadding = 10; const double _cardPadding = 10;
const double _coverWidth = 80; const double _coverWidth = 80;
const double _coverHeight = 106; const double _coverHeight = 106;
@@ -273,7 +274,7 @@ class _FavoriteCard extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColors.card, color: AppColors.card,
borderRadius: BorderRadius.circular(_cardRadius), borderRadius: BorderRadius.circular(_cardRadius),
boxShadow: const [AppTheme.cardShadow], border: Border.all(color: AppColors.border),
), ),
child: Material( child: Material(
color: AppColors.transparent, color: AppColors.transparent,
+1
View File
@@ -255,6 +255,7 @@ class _FilterPageState extends State<FilterPage> {
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColors.card, color: AppColors.card,
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColors.border),
), ),
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
+3 -14
View File
@@ -10,6 +10,7 @@ import '../../core/data/models/drama.dart';
import '../../core/data/services/catalog_controller.dart'; import '../../core/data/services/catalog_controller.dart';
import '../../core/formatting/count_format.dart'; import '../../core/formatting/count_format.dart';
import '../../core/theme/app_colors.dart'; import '../../core/theme/app_colors.dart';
import '../../core/theme/app_theme.dart';
import '../../core/widgets/app_pull_to_refresh.dart'; import '../../core/widgets/app_pull_to_refresh.dart';
import '../../core/widgets/paged_local_list.dart'; import '../../core/widgets/paged_local_list.dart';
import '../../core/widgets/remote_image.dart'; import '../../core/widgets/remote_image.dart';
@@ -107,13 +108,7 @@ class _NewReleasesPageState extends State<NewReleasesPage> {
key: const Key('new-releases-page'), key: const Key('new-releases-page'),
backgroundColor: AppColors.ink, backgroundColor: AppColors.ink,
body: DecoratedBox( body: DecoratedBox(
decoration: const BoxDecoration( decoration: const BoxDecoration(gradient: AppTheme.pageGradient),
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [AppColors.surfaceTop, AppColors.ink],
),
),
child: SafeArea( child: SafeArea(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@@ -407,13 +402,7 @@ class _NewReleasesPageState extends State<NewReleasesPage> {
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColors.card, color: AppColors.card,
borderRadius: BorderRadius.circular(_cardRadius), borderRadius: BorderRadius.circular(_cardRadius),
boxShadow: const [ border: Border.all(color: AppColors.border),
BoxShadow(
color: AppColors.cardShadow,
blurRadius: 12,
offset: Offset(0, 4),
),
],
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
+4 -1
View File
@@ -213,7 +213,10 @@ class _NoticeTile extends StatelessWidget {
return Material( return Material(
key: ValueKey('notice-item-${notice.id}'), key: ValueKey('notice-item-${notice.id}'),
color: AppColors.card, color: AppColors.card,
borderRadius: BorderRadius.circular(AppDimens.innerRadius), shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppDimens.cardRadius),
side: const BorderSide(color: AppColors.border),
),
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
child: InkWell( child: InkWell(
onTap: onTap, onTap: onTap,
+4 -4
View File
@@ -9,7 +9,7 @@ import '../../core/data/models/drama.dart';
import '../../core/data/services/catalog_controller.dart'; import '../../core/data/services/catalog_controller.dart';
import '../../core/formatting/count_format.dart'; import '../../core/formatting/count_format.dart';
import '../../core/theme/app_colors.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/app_pull_to_refresh.dart';
import '../../core/widgets/empty_state.dart'; import '../../core/widgets/empty_state.dart';
import '../../core/widgets/paged_local_list.dart'; import '../../core/widgets/paged_local_list.dart';
@@ -341,12 +341,12 @@ class _RankingRow extends StatelessWidget {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColors.card, color: AppColors.card,
borderRadius: BorderRadius.circular(14), borderRadius: BorderRadius.circular(AppDimens.cardRadius),
boxShadow: const [AppTheme.cardShadow], border: Border.all(color: AppColors.border),
), ),
child: Material( child: Material(
color: AppColors.transparent, color: AppColors.transparent,
borderRadius: BorderRadius.circular(14), borderRadius: BorderRadius.circular(AppDimens.cardRadius),
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
child: InkWell( child: InkWell(
key: Key('ranking-row-$index'), key: Key('ranking-row-$index'),
+3 -1
View File
@@ -5,12 +5,13 @@ import 'package:provider/provider.dart';
import '../../core/data/services/catalog_controller.dart'; import '../../core/data/services/catalog_controller.dart';
import '../../core/theme/app_colors.dart'; import '../../core/theme/app_colors.dart';
import '../../core/theme/app_dimens.dart';
import '../../core/widgets/app_pull_to_refresh.dart'; import '../../core/widgets/app_pull_to_refresh.dart';
import '../../core/widgets/subpage_header.dart'; import '../../core/widgets/subpage_header.dart';
import '../../l10n/app_localizations.dart'; import '../../l10n/app_localizations.dart';
import '../new_releases/new_releases_page.dart'; import '../new_releases/new_releases_page.dart';
const double _ticketRadius = 20; const double _ticketRadius = AppDimens.cardRadius;
const double _notchSize = 24; const double _notchSize = 24;
const Color _ticketDash = AppColors.primaryBorder; const Color _ticketDash = AppColors.primaryBorder;
@@ -163,6 +164,7 @@ class _ReservePageState extends State<ReservePage> {
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColors.card, color: AppColors.card,
borderRadius: BorderRadius.circular(_ticketRadius), borderRadius: BorderRadius.circular(_ticketRadius),
border: Border.all(color: AppColors.border),
), ),
child: Column( child: Column(
children: [ children: [
+5 -1
View File
@@ -7,6 +7,7 @@ import 'package:provider/provider.dart';
import '../../core/data/services/auth_controller.dart'; import '../../core/data/services/auth_controller.dart';
import '../../core/theme/app_colors.dart'; import '../../core/theme/app_colors.dart';
import '../../core/theme/app_dimens.dart';
import '../../core/theme/app_theme.dart'; import '../../core/theme/app_theme.dart';
import '../../core/widgets/auth_gate.dart'; import '../../core/widgets/auth_gate.dart';
import '../../core/widgets/plain_page_scaffold.dart'; import '../../core/widgets/plain_page_scaffold.dart';
@@ -47,7 +48,10 @@ class SettingsPage extends StatelessWidget {
Widget _noticesTile(BuildContext context, AppLocalizations l10n) { Widget _noticesTile(BuildContext context, AppLocalizations l10n) {
return Material( return Material(
color: AppColors.card, color: AppColors.card,
borderRadius: BorderRadius.circular(14), shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppDimens.cardRadius),
side: const BorderSide(color: AppColors.border),
),
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
child: ListTile( child: ListTile(
key: const Key('settings-notices'), key: const Key('settings-notices'),
+2 -2
View File
@@ -151,8 +151,8 @@ class _ProductTile extends StatelessWidget {
padding: const EdgeInsets.fromLTRB(14, 14, 12, 14), padding: const EdgeInsets.fromLTRB(14, 14, 12, 14),
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColors.card, color: AppColors.card,
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(AppDimens.cardRadius),
border: Border.all(color: AppColors.gold.withValues(alpha: 0.26)), border: Border.all(color: AppColors.border),
), ),
child: Row( child: Row(
children: [ children: [
+3 -14
View File
@@ -183,20 +183,9 @@ class _BalanceHero extends StatelessWidget {
key: const Key('wallet-balance-card'), key: const Key('wallet-balance-card'),
padding: const EdgeInsets.fromLTRB(20, 22, 20, 20), padding: const EdgeInsets.fromLTRB(20, 22, 20, 20),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20), color: AppColors.card,
gradient: const LinearGradient( borderRadius: BorderRadius.circular(AppDimens.cardRadius),
begin: Alignment.topLeft, border: Border.all(color: AppColors.border),
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),
),
],
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@@ -5,11 +5,11 @@ import 'package:flutter/material.dart';
import '../../../core/data/models/watch_record.dart'; import '../../../core/data/models/watch_record.dart';
import '../../../core/formatting/localized_date_time.dart'; import '../../../core/formatting/localized_date_time.dart';
import '../../../core/theme/app_colors.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 '../../../core/widgets/remote_image.dart';
import '../../../l10n/app_localizations.dart'; import '../../../l10n/app_localizations.dart';
const double _cardRadius = 14; const double _cardRadius = AppDimens.cardRadius;
const double _cardPadding = 10; const double _cardPadding = 10;
const double _coverWidth = 72; const double _coverWidth = 72;
const double _coverHeight = 96; const double _coverHeight = 96;
@@ -187,7 +187,7 @@ class WatchRecordCard extends StatelessWidget {
BoxDecoration _cardDecoration() => BoxDecoration( BoxDecoration _cardDecoration() => BoxDecoration(
color: AppColors.card, color: AppColors.card,
borderRadius: BorderRadius.circular(_cardRadius), borderRadius: BorderRadius.circular(_cardRadius),
boxShadow: const [AppTheme.cardShadow], border: Border.all(color: AppColors.border),
); );
Widget _removeButton(String tooltip) { Widget _removeButton(String tooltip) {
@@ -227,7 +227,7 @@ class _FailedRecordTile extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppColors.card, color: AppColors.card,
borderRadius: BorderRadius.circular(_cardRadius), borderRadius: BorderRadius.circular(_cardRadius),
boxShadow: const [AppTheme.cardShadow], border: Border.all(color: AppColors.border),
), ),
child: Container( child: Container(
key: ValueKey('watch-record-failed-${record.dramaId}'), key: ValueKey('watch-record-failed-${record.dramaId}'),
+4 -6
View File
@@ -28,7 +28,7 @@ void main() {
final title = tester.widget<Text>(find.byKey(const Key('subpage-title'))); final title = tester.widget<Text>(find.byKey(const Key('subpage-title')));
expect(title.style?.fontSize, 18); expect(title.style?.fontSize, 18);
expect(title.style?.fontWeight, FontWeight.w800); 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 back = tester.getRect(find.byKey(const Key('sample-back')));
final titleRect = tester.getRect(find.byKey(const Key('subpage-title'))); final titleRect = tester.getRect(find.byKey(const Key('subpage-title')));
expect(titleRect.left - back.right, closeTo(12, 0.5)); expect(titleRect.left - back.right, closeTo(12, 0.5));
@@ -38,8 +38,8 @@ void main() {
matching: find.byType(Material), matching: find.byType(Material),
), ),
); );
expect(surface.color, AppColors.card); expect(surface.color, AppColors.transparent);
expect((surface.shape! as CircleBorder).side.color, AppColors.border); expect((surface.shape! as CircleBorder).side, BorderSide.none);
final shadow = final shadow =
tester tester
.widget<DecoratedBox>( .widget<DecoratedBox>(
@@ -47,9 +47,7 @@ void main() {
) )
.decoration .decoration
as BoxDecoration; as BoxDecoration;
expect(shadow.boxShadow!.single.color, AppColors.shadowSubtle); expect(shadow.boxShadow, isEmpty);
expect(shadow.boxShadow!.single.blurRadius, 8);
expect(shadow.boxShadow!.single.offset, const Offset(0, 2));
}); });
testWidgets('should_use_64_height_when_subtitle_exists', (tester) async { testWidgets('should_use_64_height_when_subtitle_exists', (tester) async {
@@ -94,7 +94,8 @@ void main() {
); );
final statsDecoration = stats.decoration! as BoxDecoration; final statsDecoration = stats.decoration! as BoxDecoration;
expect(statsDecoration.color, AppColors.card); 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-synopsis-section')), findsOneWidget);
expect(find.byKey(const Key('detail-tags')), findsOneWidget); expect(find.byKey(const Key('detail-tags')), findsOneWidget);
expect(find.byKey(const Key('detail-episodes-section')), findsOneWidget); expect(find.byKey(const Key('detail-episodes-section')), findsOneWidget);
+16 -7
View File
@@ -20,11 +20,15 @@ void main() {
test('should_expose_dark_visual_tokens', () { test('should_expose_dark_visual_tokens', () {
expect(AppColors.blue, const Color(0xFFFF6B2C)); expect(AppColors.blue, const Color(0xFFFF6B2C));
expect(AppColors.bluePressed, const Color(0xFFE55A1F)); expect(AppColors.bluePressed, const Color(0xFFE55A1F));
expect(AppColors.secondary, const Color(0xFF22D3EE)); expect(AppColors.secondary, const Color(0xFFB0B0B0));
expect(AppColors.ink, const Color(0xFF0B1020)); expect(AppColors.ink, const Color(0xFF000000));
expect(AppColors.card, const Color(0xFF151B2E)); expect(AppColors.card, const Color(0xFF16161A));
expect(AppColors.raised, const Color(0xFF1C2436)); expect(AppColors.cardAlt, const Color(0xFF101010));
expect(AppColors.border, const Color(0x0FFFFFFF)); 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.onSurface, const Color(0xEBFFFFFF));
expect(AppColors.muted, const Color(0xA3FFFFFF)); expect(AppColors.muted, const Color(0xA3FFFFFF));
expect(AppColors.subtle, const Color(0x61FFFFFF)); expect(AppColors.subtle, const Color(0x61FFFFFF));
@@ -59,7 +63,7 @@ void main() {
expect(theme.colorScheme.onSurface, AppColors.onSurface); expect(theme.colorScheme.onSurface, AppColors.onSurface);
expect(theme.colorScheme.outline, AppColors.border); expect(theme.colorScheme.outline, AppColors.border);
expect(theme.scaffoldBackgroundColor, AppColors.ink); 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.appBarTheme.systemOverlayStyle, SystemUiOverlayStyle.light);
expect(theme.cardTheme.elevation, 0); expect(theme.cardTheme.elevation, 0);
expect(theme.dialogTheme.backgroundColor, AppColors.raised); expect(theme.dialogTheme.backgroundColor, AppColors.raised);
@@ -91,7 +95,12 @@ void main() {
}); });
test('should_expose_flat_page_gradient_without_card_shadow', () { 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.color, AppColors.cardShadow);
expect(AppTheme.cardShadow.blurRadius, 0); expect(AppTheme.cardShadow.blurRadius, 0);
expect(AppTheme.cardShadow.offset, Offset.zero); expect(AppTheme.cardShadow.offset, Offset.zero);
+1 -1
View File
@@ -65,7 +65,7 @@ void main() {
final theme = Theme.of(context); final theme = Theme.of(context);
expect(theme.brightness, Brightness.dark); expect(theme.brightness, Brightness.dark);
expect(theme.scaffoldBackgroundColor, AppColors.ink); expect(theme.scaffoldBackgroundColor, AppColors.ink);
expect(theme.appBarTheme.backgroundColor, AppColors.card); expect(theme.appBarTheme.backgroundColor, AppColors.transparent);
expect(theme.cardTheme.color, AppColors.card); expect(theme.cardTheme.color, AppColors.card);
final card = tester.widget<Card>(find.byKey(const Key('dark-smoke-card'))); final card = tester.widget<Card>(find.byKey(const Key('dark-smoke-card')));