feat(flutter): 应用浅色暖橙视觉主题
This commit is contained in:
1 parent
0d2367431d
commit
634b63e16c
56 files changed
+941
-409
No files matched your search
@@ -50,7 +50,7 @@ class _AccountDeactivatePageState extends State<AccountDeactivatePage> {
|
||||
final signedIn = context.watch<AuthController>().isSignedIn;
|
||||
final canShow = signedIn || _logic.scheduledAt != null;
|
||||
return Theme(
|
||||
data: AppTheme.dark(),
|
||||
data: AppTheme.light(),
|
||||
child: Scaffold(
|
||||
key: const Key('account-deactivate-page'),
|
||||
backgroundColor: AppColors.ink,
|
||||
|
||||
@@ -50,7 +50,7 @@ class _AccountDevicesPageState extends State<AccountDevicesPage> {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final signedIn = context.watch<AuthController>().isSignedIn;
|
||||
return Theme(
|
||||
data: AppTheme.dark(),
|
||||
data: AppTheme.light(),
|
||||
child: Scaffold(
|
||||
key: const Key('account-devices-page'),
|
||||
backgroundColor: AppColors.ink,
|
||||
|
||||
@@ -51,7 +51,7 @@ class _AccountExportPageState extends State<AccountExportPage> {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final signedIn = context.watch<AuthController>().isSignedIn;
|
||||
return Theme(
|
||||
data: AppTheme.dark(),
|
||||
data: AppTheme.light(),
|
||||
child: Scaffold(
|
||||
key: const Key('account-export-page'),
|
||||
backgroundColor: AppColors.ink,
|
||||
|
||||
@@ -71,7 +71,7 @@ class _AccountProfilePageState extends State<AccountProfilePage> {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final signedIn = context.watch<AuthController>().isSignedIn;
|
||||
return Theme(
|
||||
data: AppTheme.dark(),
|
||||
data: AppTheme.light(),
|
||||
child: Scaffold(
|
||||
key: const Key('account-profile-page'),
|
||||
backgroundColor: AppColors.ink,
|
||||
|
||||
@@ -141,7 +141,7 @@ class _AuthPageState extends State<AuthPage> {
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return Theme(
|
||||
data: AppTheme.dark(),
|
||||
data: AppTheme.light(),
|
||||
child: Scaffold(
|
||||
resizeToAvoidBottomInset: true,
|
||||
backgroundColor: AppColors.ink,
|
||||
@@ -332,7 +332,7 @@ class _AuthPageState extends State<AuthPage> {
|
||||
Text(
|
||||
l10n.authLandingSubtitle,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(color: Color(0xFF9A96A3), fontSize: 11),
|
||||
style: const TextStyle(color: AppColors.subtle, fontSize: 11),
|
||||
),
|
||||
const SizedBox(height: 22),
|
||||
_AuthEntryButton(
|
||||
@@ -358,7 +358,7 @@ class _AuthPageState extends State<AuthPage> {
|
||||
key: const Key('auth-legal'),
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF6B6772),
|
||||
color: AppColors.muted,
|
||||
fontSize: 9,
|
||||
height: 1.6,
|
||||
),
|
||||
@@ -442,8 +442,7 @@ class _AuthEntryButton extends StatelessWidget {
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (icon != null)
|
||||
Icon(icon, size: 16, color: foreground),
|
||||
if (icon != null) Icon(icon, size: 16, color: foreground),
|
||||
if (icon != null) const SizedBox(width: 7),
|
||||
Flexible(
|
||||
child: Text(
|
||||
|
||||
@@ -7,7 +7,7 @@ import '../../core/theme/app_dimens.dart';
|
||||
import '../../core/theme/app_theme.dart';
|
||||
import '../../l10n/app_localizations.dart';
|
||||
|
||||
/// K28-A1 placeholder for the future creation workspace.
|
||||
/// K28-A1 创作页占位骨架。
|
||||
class CreatePage extends StatelessWidget {
|
||||
const CreatePage({super.key});
|
||||
|
||||
@@ -15,7 +15,7 @@ class CreatePage extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return Theme(
|
||||
data: AppTheme.dark(),
|
||||
data: AppTheme.light(),
|
||||
child: SafeArea(
|
||||
bottom: false,
|
||||
child: Padding(
|
||||
|
||||
@@ -27,7 +27,7 @@ class CategoryDramasPage extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return Theme(
|
||||
data: AppTheme.dark(),
|
||||
data: AppTheme.light(),
|
||||
child: Scaffold(
|
||||
key: const Key('category-dramas-page'),
|
||||
backgroundColor: AppColors.ink,
|
||||
|
||||
@@ -108,9 +108,9 @@ class _DiscoverPageState extends State<DiscoverPage> {
|
||||
),
|
||||
);
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle.light,
|
||||
value: SystemUiOverlayStyle.dark,
|
||||
child: Theme(
|
||||
data: AppTheme.dark(),
|
||||
data: AppTheme.light(),
|
||||
child: embedded
|
||||
? content
|
||||
: Scaffold(backgroundColor: AppColors.ink, body: content),
|
||||
@@ -340,6 +340,10 @@ class _DiscoverPageState extends State<DiscoverPage> {
|
||||
}
|
||||
|
||||
Widget _bottomNav(AppLocalizations l10n) => AppBottomNav(
|
||||
centerAction: AppBottomNavCenterAction(
|
||||
label: l10n.createTab,
|
||||
onTap: () => _act(DiscoverPageAction.create),
|
||||
),
|
||||
items: [
|
||||
AppBottomNavItem(
|
||||
tabKey: const Key('discover-nav-home'),
|
||||
|
||||
@@ -88,12 +88,12 @@ class DiscoverHeader extends StatelessWidget {
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [Color(0xFF6A5CFF), AppColors.blue],
|
||||
colors: [AppColors.secondary, AppColors.blue],
|
||||
),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.person_rounded,
|
||||
color: AppColors.onSurface,
|
||||
color: AppColors.onPrimary,
|
||||
size: 18,
|
||||
),
|
||||
),
|
||||
@@ -124,7 +124,7 @@ class _HeaderIcon extends StatelessWidget {
|
||||
onPressed: onTap,
|
||||
padding: EdgeInsets.zero,
|
||||
style: IconButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF2C2D33),
|
||||
backgroundColor: AppColors.raised,
|
||||
foregroundColor: AppColors.onSurface,
|
||||
),
|
||||
icon: Icon(icon, size: 18),
|
||||
|
||||
@@ -5,11 +5,15 @@ import 'package:flutter/material.dart';
|
||||
import '../../../core/config/app_config.dart';
|
||||
import '../../../core/data/models/drama.dart';
|
||||
import '../../../core/theme/app_colors.dart';
|
||||
import '../../../core/theme/app_dimens.dart';
|
||||
import '../../../core/theme/app_theme.dart';
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
|
||||
const int _columns = 2;
|
||||
const double _columnGap = 10;
|
||||
const double _cardGap = 10;
|
||||
const double _addSize = 28;
|
||||
const double _addIconSize = 18;
|
||||
|
||||
/// 剧场/分类页共用的双列剧目网格。
|
||||
class DramaGrid extends StatelessWidget {
|
||||
@@ -71,19 +75,33 @@ class DramaGridCard extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
key: Key('home-drama-card-${drama.id}'),
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_cover(),
|
||||
const SizedBox(height: 5),
|
||||
_title(),
|
||||
const SizedBox(height: 2),
|
||||
_genre(),
|
||||
],
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.card,
|
||||
borderRadius: BorderRadius.circular(AppDimens.cardRadius),
|
||||
boxShadow: const [AppTheme.cardShadow],
|
||||
),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(AppDimens.cardRadius),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: InkWell(
|
||||
key: Key('home-drama-card-${drama.id}'),
|
||||
onTap: onTap,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(AppDimens.spaceSm),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_cover(),
|
||||
const SizedBox(height: AppDimens.spaceSm),
|
||||
_title(),
|
||||
const SizedBox(height: AppDimens.spaceXs),
|
||||
_footer(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -94,34 +112,90 @@ class DramaGridCard extends StatelessWidget {
|
||||
drama.episodes.any((episode) => episode.isFree);
|
||||
return ClipRRect(
|
||||
key: Key('home-drama-cover-${drama.id}'),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
borderRadius: BorderRadius.circular(AppDimens.coverRadius),
|
||||
child: Stack(
|
||||
children: [
|
||||
_DiscoverCoverImage(path: drama.posterUrl),
|
||||
if (free) Positioned(top: 6, left: 6, child: _freeBadge()),
|
||||
Positioned(top: 8, left: 8, child: _tagBadge(free)),
|
||||
if (_lockedCount > 0)
|
||||
Positioned(top: 8, right: 8, child: _lockedBadge()),
|
||||
Positioned(right: 8, bottom: 8, child: _episodeBadge()),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _freeBadge() {
|
||||
int get _lockedCount {
|
||||
final explicit = drama.episodes.where((episode) => episode.locked).length;
|
||||
if (explicit > 0) return explicit;
|
||||
final inferred = drama.episodeCount - drama.freeEpisodes;
|
||||
return inferred > 0 ? inferred : 0;
|
||||
}
|
||||
|
||||
Widget _tagBadge(bool free) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||
key: Key('drama-tag-${drama.id}'),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.blue,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
color: AppColors.badgePink,
|
||||
borderRadius: BorderRadius.circular(AppDimens.pillRadius),
|
||||
),
|
||||
child: Text(
|
||||
l10n.free,
|
||||
free ? l10n.free : l10n.originalTag,
|
||||
style: const TextStyle(
|
||||
color: AppColors.onPrimary,
|
||||
fontSize: 8,
|
||||
color: AppColors.badgePinkText,
|
||||
fontSize: AppDimens.cardMeta,
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _lockedBadge() {
|
||||
return Container(
|
||||
key: Key('drama-locked-${drama.id}'),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 3),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.overlayDark,
|
||||
borderRadius: BorderRadius.circular(AppDimens.pillRadius),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.lock_rounded, color: AppColors.onPrimary, size: 11),
|
||||
const SizedBox(width: 2),
|
||||
Text(
|
||||
l10n.lockedEpisodeCount(_lockedCount),
|
||||
style: const TextStyle(
|
||||
color: AppColors.onPrimary,
|
||||
fontSize: 9,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _episodeBadge() {
|
||||
return Container(
|
||||
key: Key('drama-episodes-badge-${drama.id}'),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.badgeBeige,
|
||||
borderRadius: BorderRadius.circular(AppDimens.pillRadius),
|
||||
),
|
||||
child: Text(
|
||||
l10n.allEpisodesBadge(drama.episodeCount),
|
||||
style: const TextStyle(
|
||||
color: AppColors.onSurface,
|
||||
fontSize: 9,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _title() {
|
||||
return Text(
|
||||
drama.title,
|
||||
@@ -130,7 +204,7 @@ class DramaGridCard extends StatelessWidget {
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: AppColors.onSurface,
|
||||
fontSize: 11,
|
||||
fontSize: AppDimens.cardTitle,
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
);
|
||||
@@ -143,7 +217,32 @@ class DramaGridCard extends StatelessWidget {
|
||||
key: Key('home-drama-genre-${drama.id}'),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(color: Color(0xFFBBBBBB), fontSize: 9),
|
||||
style: const TextStyle(
|
||||
color: AppColors.muted,
|
||||
fontSize: AppDimens.cardMeta,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _footer() {
|
||||
return Row(
|
||||
children: [
|
||||
Expanded(child: _genre()),
|
||||
Container(
|
||||
key: Key('drama-add-${drama.id}'),
|
||||
width: _addSize,
|
||||
height: _addSize,
|
||||
decoration: const BoxDecoration(
|
||||
color: AppColors.blue,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.add_rounded,
|
||||
color: AppColors.onPrimary,
|
||||
size: _addIconSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ class _RankingSectionState extends State<RankingSection> {
|
||||
final selected = logic.board == board;
|
||||
return Material(
|
||||
key: key,
|
||||
color: selected ? AppColors.blue : AppColors.raised,
|
||||
color: selected ? AppColors.blue : AppColors.card,
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: InkWell(
|
||||
@@ -145,7 +145,7 @@ class _RankingSectionState extends State<RankingSection> {
|
||||
child: Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
color: selected ? AppColors.onPrimary : AppColors.muted,
|
||||
color: selected ? AppColors.onPrimary : AppColors.onSurface,
|
||||
fontSize: 9,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
|
||||
@@ -54,7 +54,7 @@ class _DownloadsPageState extends State<DownloadsPage> {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final signedIn = context.watch<AuthController>().isSignedIn;
|
||||
return Theme(
|
||||
data: AppTheme.dark(),
|
||||
data: AppTheme.light(),
|
||||
child: Scaffold(
|
||||
key: const Key('downloads-page'),
|
||||
backgroundColor: AppColors.ink,
|
||||
@@ -168,11 +168,8 @@ class _DownloadsBody extends StatelessWidget {
|
||||
);
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (_) => PlayerPage(
|
||||
drama: drama,
|
||||
initialIndex: 0,
|
||||
downloads: downloads,
|
||||
),
|
||||
builder: (_) =>
|
||||
PlayerPage(drama: drama, initialIndex: 0, downloads: downloads),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ class _DramaDetailPageState extends State<DramaDetailPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Theme(
|
||||
data: AppTheme.dark(),
|
||||
data: AppTheme.light(),
|
||||
child: ListenableBuilder(
|
||||
listenable: logic,
|
||||
builder: (context, _) => _page(context),
|
||||
@@ -171,7 +171,7 @@ class _DramaDetailPageState extends State<DramaDetailPage> {
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [Color(0x33000000), Color(0xCC0B0C10)],
|
||||
colors: [Color(0x33000000), AppColors.onSurface],
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -363,7 +363,7 @@ class _DramaDetailPageState extends State<DramaDetailPage> {
|
||||
? AppColors.blue
|
||||
: locked
|
||||
? AppColors.secondary.withValues(alpha: 0.16)
|
||||
: const Color(0xFF29272B),
|
||||
: AppColors.raised,
|
||||
borderRadius: BorderRadius.circular(9),
|
||||
),
|
||||
child: Text(
|
||||
@@ -461,8 +461,8 @@ class _DramaDetailPageState extends State<DramaDetailPage> {
|
||||
child: Container(
|
||||
width: 36,
|
||||
height: 36,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0x80000000),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.card.withValues(alpha: 0.92),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
@@ -562,8 +562,8 @@ class _RoundAction extends StatelessWidget {
|
||||
return Container(
|
||||
width: 36,
|
||||
height: 36,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0x80000000),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.card.withValues(alpha: 0.92),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: IconButton(
|
||||
@@ -592,7 +592,7 @@ class _ResumeBar extends StatelessWidget {
|
||||
child: LinearProgressIndicator(
|
||||
value: fraction,
|
||||
minHeight: 3,
|
||||
backgroundColor: const Color(0xFF474248),
|
||||
backgroundColor: AppColors.border,
|
||||
valueColor: const AlwaysStoppedAnimation(AppColors.blue),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -51,7 +51,7 @@ class _FavoritesPageState extends State<FavoritesPage> {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final signedIn = context.watch<AuthController>().isSignedIn;
|
||||
return Theme(
|
||||
data: AppTheme.dark(),
|
||||
data: AppTheme.light(),
|
||||
child: Scaffold(
|
||||
backgroundColor: AppColors.ink,
|
||||
appBar: AppBar(
|
||||
|
||||
@@ -7,10 +7,10 @@ import 'package:flutter/foundation.dart';
|
||||
import '../../core/data/models/watch_progress.dart';
|
||||
import '../../core/data/repositories/watch_history_repository.dart';
|
||||
|
||||
/// Home browse channel, backed only by data already present in the catalogue.
|
||||
/// 首页频道,只依赖目录中已有数据排序或过滤。
|
||||
enum HomeChannel { hot, free, newReleases, ranking }
|
||||
|
||||
/// Local UI state for the browse-first home page.
|
||||
/// 浏览型首页的本地 UI 状态。
|
||||
class HomeBrowseLogic extends ChangeNotifier {
|
||||
HomeBrowseLogic({required this.history}) {
|
||||
unawaited(refreshRecent());
|
||||
@@ -24,7 +24,7 @@ class HomeBrowseLogic extends ChangeNotifier {
|
||||
bool loadingRecent = false;
|
||||
bool _disposed = false;
|
||||
|
||||
/// First unfinished record with a real position.
|
||||
/// 第一条未完成且存在真实播放位置的记录。
|
||||
WatchProgress? get primaryRecord {
|
||||
for (final record in recent) {
|
||||
if (!record.finished && record.hasPosition) return record;
|
||||
@@ -32,14 +32,14 @@ class HomeBrowseLogic extends ChangeNotifier {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Changes the selected browse channel without triggering network work.
|
||||
/// 切换频道,不触发额外网络请求。
|
||||
void selectChannel(HomeChannel value) {
|
||||
if (channel == value) return;
|
||||
channel = value;
|
||||
_notify();
|
||||
}
|
||||
|
||||
/// Reloads continuation data; signed-out reads simply return an empty list.
|
||||
/// 重新加载续看数据;未登录时返回空列表。
|
||||
Future<void> refreshRecent() async {
|
||||
loadingRecent = true;
|
||||
_notify();
|
||||
@@ -53,7 +53,7 @@ class HomeBrowseLogic extends ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
/// Refreshes continuation data when the home tab becomes visible again.
|
||||
/// 首页重新可见时刷新续看数据。
|
||||
void syncPage({required bool active, required bool wasActive}) {
|
||||
if (active && !wasActive) unawaited(refreshRecent());
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import 'home_browse_logic.dart';
|
||||
import 'widgets/home_browse_header.dart';
|
||||
import 'widgets/home_drama_grid.dart';
|
||||
|
||||
/// Browse-first home page with channels, hero, continuation, and catalogue.
|
||||
/// 浏览型首页:频道、Hero、继续观看与剧目目录。
|
||||
class HomeBrowseView extends StatefulWidget {
|
||||
const HomeBrowseView({
|
||||
super.key,
|
||||
@@ -214,7 +214,7 @@ class _HomeBrowseViewState extends State<HomeBrowseView> {
|
||||
color: selected ? AppColors.blue : AppColors.border,
|
||||
),
|
||||
labelStyle: TextStyle(
|
||||
color: selected ? AppColors.onPrimary : AppColors.muted,
|
||||
color: selected ? AppColors.onPrimary : AppColors.onSurface,
|
||||
fontSize: AppDimens.chipFont,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
|
||||
@@ -8,7 +8,6 @@ import 'package:provider/provider.dart';
|
||||
import '../../core/data/models/drama.dart';
|
||||
import '../../core/data/services/catalog_controller.dart';
|
||||
import '../../core/platform/haptics.dart';
|
||||
import '../../core/theme/app_colors.dart';
|
||||
import '../../core/theme/app_theme.dart';
|
||||
import '../../core/widgets/app_bottom_nav.dart';
|
||||
import '../../core/widgets/empty_state.dart';
|
||||
@@ -32,8 +31,11 @@ class HomePage extends StatelessWidget {
|
||||
if (!catalog.settled) return const SplashPage();
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return Theme(
|
||||
data: AppTheme.dark(),
|
||||
child: _buildHome(context, catalog, l10n),
|
||||
data: AppTheme.light(),
|
||||
child: DecoratedBox(
|
||||
decoration: const BoxDecoration(gradient: AppTheme.pageGradient),
|
||||
child: _buildHome(context, catalog, l10n),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,19 +46,19 @@ class HomePage extends StatelessWidget {
|
||||
) {
|
||||
if (catalog.loading) {
|
||||
return const Scaffold(
|
||||
backgroundColor: AppColors.ink,
|
||||
backgroundColor: Colors.transparent,
|
||||
body: Center(child: CircularProgressIndicator()),
|
||||
);
|
||||
}
|
||||
if (catalog.error != null) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.ink,
|
||||
backgroundColor: Colors.transparent,
|
||||
body: HomeFailureView(onRetry: catalog.load),
|
||||
);
|
||||
}
|
||||
if (catalog.dramas.isEmpty) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.ink,
|
||||
backgroundColor: Colors.transparent,
|
||||
body: EmptyState(
|
||||
key: const Key('home-empty'),
|
||||
icon: Icons.movie_outlined,
|
||||
@@ -75,7 +77,7 @@ class HomePage extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/// Home catalog failure with a single recovery action.
|
||||
/// 首页目录加载失败与重试入口。
|
||||
class HomeFailureView extends StatelessWidget {
|
||||
const HomeFailureView({super.key, required this.onRetry});
|
||||
|
||||
@@ -93,7 +95,7 @@ class HomeFailureView extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/// The four primary destinations share a single route and keep their state.
|
||||
/// 四个根页面共享同一路由并保持各自状态。
|
||||
class _HomeTabs extends StatefulWidget {
|
||||
const _HomeTabs({super.key, required this.dramas});
|
||||
|
||||
@@ -136,7 +138,7 @@ class _HomeTabsState extends State<_HomeTabs> {
|
||||
},
|
||||
child: Scaffold(
|
||||
key: logic.scaffoldKey,
|
||||
backgroundColor: AppColors.ink,
|
||||
backgroundColor: Colors.transparent,
|
||||
body: _body(context),
|
||||
bottomNavigationBar: logic.videoImmersive ? null : _nav(context, l10n),
|
||||
),
|
||||
@@ -193,6 +195,10 @@ class _HomeTabsState extends State<_HomeTabs> {
|
||||
Widget _nav(BuildContext context, AppLocalizations l10n) {
|
||||
return AppBottomNav(
|
||||
barKey: const Key('home-tabs-bar'),
|
||||
centerAction: AppBottomNavCenterAction(
|
||||
label: l10n.createTab,
|
||||
onTap: () => _selectTab(context, 2),
|
||||
),
|
||||
items: [
|
||||
_navItem(context, l10n, 0),
|
||||
_navItem(context, l10n, 1),
|
||||
|
||||
@@ -8,7 +8,7 @@ import '../../../l10n/app_localizations.dart';
|
||||
|
||||
const double _searchHeight = 36;
|
||||
|
||||
/// Fixed home header with catalogue search, weekday, and profile entry.
|
||||
/// 首页固定顶栏:搜索、星期与头像入口。
|
||||
class HomeBrowseHeader extends StatelessWidget {
|
||||
const HomeBrowseHeader({
|
||||
super.key,
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
|
||||
import '../../../core/data/models/drama.dart';
|
||||
import '../../../core/theme/app_colors.dart';
|
||||
import '../../../core/theme/app_dimens.dart';
|
||||
import '../../../core/theme/app_theme.dart';
|
||||
import '../../../core/widgets/remote_image.dart';
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
|
||||
@@ -12,8 +13,10 @@ const int _columns = 2;
|
||||
const double _columnGap = 10;
|
||||
const double _cardGap = 10;
|
||||
const double _coverAspectRatio = 3 / 4;
|
||||
const double _addSize = 28;
|
||||
const double _addIconSize = 18;
|
||||
|
||||
/// Two-column drama grid used by the browse-first home page.
|
||||
/// 首页浏览态使用的双列剧目网格。
|
||||
class HomeDramaGrid extends StatelessWidget {
|
||||
const HomeDramaGrid({
|
||||
super.key,
|
||||
@@ -57,7 +60,7 @@ class HomeDramaGrid extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/// Home catalogue card with title, genre, free badge, episode count, and heat.
|
||||
/// 首页剧卡:封面、角标、标题、题材、集数与热度。
|
||||
class HomeDramaCard extends StatelessWidget {
|
||||
const HomeDramaCard({
|
||||
super.key,
|
||||
@@ -72,21 +75,35 @@ class HomeDramaCard extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return InkWell(
|
||||
key: Key('home-drama-card-${drama.id}'),
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(AppDimens.coverRadius),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_cover(),
|
||||
const SizedBox(height: AppDimens.spaceXs),
|
||||
_title(),
|
||||
const SizedBox(height: 2),
|
||||
_genre(),
|
||||
const SizedBox(height: AppDimens.spaceXs),
|
||||
_metadata(),
|
||||
],
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.card,
|
||||
borderRadius: BorderRadius.circular(AppDimens.cardRadius),
|
||||
boxShadow: const [AppTheme.cardShadow],
|
||||
),
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(AppDimens.cardRadius),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: InkWell(
|
||||
key: Key('home-drama-card-${drama.id}'),
|
||||
onTap: onTap,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(AppDimens.spaceSm),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
_cover(),
|
||||
const SizedBox(height: AppDimens.spaceSm),
|
||||
_title(),
|
||||
const SizedBox(height: AppDimens.spaceXs),
|
||||
_genre(),
|
||||
const SizedBox(height: AppDimens.spaceXs),
|
||||
_metadata(),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -104,7 +121,10 @@ class HomeDramaCard extends StatelessWidget {
|
||||
showFallbackIcon: true,
|
||||
fallbackAspectRatio: _coverAspectRatio,
|
||||
),
|
||||
if (_isFree) Positioned(top: 6, left: 6, child: _freeBadge()),
|
||||
Positioned(top: 8, left: 8, child: _tagBadge()),
|
||||
if (_lockedCount > 0)
|
||||
Positioned(top: 8, right: 8, child: _lockedBadge()),
|
||||
Positioned(right: 8, bottom: 8, child: _episodeBadge()),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -115,17 +135,29 @@ class HomeDramaCard extends StatelessWidget {
|
||||
drama.episodes.any((episode) => episode.isFree);
|
||||
}
|
||||
|
||||
Widget _freeBadge() {
|
||||
int get _lockedCount {
|
||||
final explicit = drama.episodes.where((episode) => episode.locked).length;
|
||||
if (explicit > 0) return explicit;
|
||||
final inferred = drama.episodeCount - drama.freeEpisodes;
|
||||
return inferred > 0 ? inferred : 0;
|
||||
}
|
||||
|
||||
Widget _tagBadge() {
|
||||
final label = _isFree ? l10n.free : l10n.originalTag;
|
||||
return Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||
key: Key('home-drama-tag-${drama.id}'),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: AppDimens.spaceSm,
|
||||
vertical: 3,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.blue,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
color: AppColors.badgePink,
|
||||
borderRadius: BorderRadius.circular(AppDimens.pillRadius),
|
||||
),
|
||||
child: Text(
|
||||
l10n.free,
|
||||
label,
|
||||
style: const TextStyle(
|
||||
color: AppColors.onPrimary,
|
||||
color: AppColors.badgePinkText,
|
||||
fontSize: AppDimens.cardMeta,
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
@@ -133,6 +165,51 @@ class HomeDramaCard extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _lockedBadge() {
|
||||
return Container(
|
||||
key: Key('home-drama-locked-${drama.id}'),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 3),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.overlayDark,
|
||||
borderRadius: BorderRadius.circular(AppDimens.pillRadius),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.lock_rounded, color: AppColors.onPrimary, size: 11),
|
||||
const SizedBox(width: 2),
|
||||
Text(
|
||||
l10n.lockedEpisodeCount(_lockedCount),
|
||||
style: const TextStyle(
|
||||
color: AppColors.onPrimary,
|
||||
fontSize: 9,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _episodeBadge() {
|
||||
return Container(
|
||||
key: Key('home-drama-episodes-badge-${drama.id}'),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.badgeBeige,
|
||||
borderRadius: BorderRadius.circular(AppDimens.pillRadius),
|
||||
),
|
||||
child: Text(
|
||||
l10n.allEpisodesBadge(drama.episodeCount),
|
||||
style: const TextStyle(
|
||||
color: AppColors.onSurface,
|
||||
fontSize: 9,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _title() {
|
||||
return Text(
|
||||
drama.title,
|
||||
@@ -141,7 +218,7 @@ class HomeDramaCard extends StatelessWidget {
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: AppColors.onSurface,
|
||||
fontSize: AppDimens.previewSectionTitle,
|
||||
fontSize: AppDimens.cardTitle,
|
||||
fontWeight: FontWeight.w800,
|
||||
),
|
||||
);
|
||||
@@ -162,24 +239,44 @@ class HomeDramaCard extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget _metadata() {
|
||||
return Wrap(
|
||||
spacing: AppDimens.spaceSm,
|
||||
runSpacing: AppDimens.spaceXs,
|
||||
return Row(
|
||||
children: [
|
||||
Text(
|
||||
l10n.episodeCount(drama.episodeCount),
|
||||
key: Key('home-drama-episode-count-${drama.id}'),
|
||||
style: const TextStyle(
|
||||
color: AppColors.subtle,
|
||||
fontSize: AppDimens.cardViews,
|
||||
Expanded(
|
||||
child: Wrap(
|
||||
spacing: AppDimens.spaceSm,
|
||||
runSpacing: AppDimens.spaceXs,
|
||||
children: [
|
||||
Text(
|
||||
l10n.episodeCount(drama.episodeCount),
|
||||
key: Key('home-drama-episode-count-${drama.id}'),
|
||||
style: const TextStyle(
|
||||
color: AppColors.subtle,
|
||||
fontSize: AppDimens.cardViews,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
l10n.viewCountLabel(drama.viewCount),
|
||||
key: Key('home-drama-views-${drama.id}'),
|
||||
style: const TextStyle(
|
||||
color: AppColors.subtle,
|
||||
fontSize: AppDimens.cardViews,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Text(
|
||||
l10n.viewCountLabel(drama.viewCount),
|
||||
key: Key('home-drama-views-${drama.id}'),
|
||||
style: const TextStyle(
|
||||
color: AppColors.subtle,
|
||||
fontSize: AppDimens.cardViews,
|
||||
Container(
|
||||
key: Key('home-drama-add-${drama.id}'),
|
||||
width: _addSize,
|
||||
height: _addSize,
|
||||
decoration: const BoxDecoration(
|
||||
color: AppColors.blue,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.add_rounded,
|
||||
color: AppColors.onPrimary,
|
||||
size: _addIconSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -92,7 +92,7 @@ class _MyPageState extends State<MyPage> {
|
||||
),
|
||||
);
|
||||
return Theme(
|
||||
data: AppTheme.dark(),
|
||||
data: AppTheme.light(),
|
||||
child: embedded
|
||||
? content
|
||||
: Scaffold(backgroundColor: AppColors.ink, body: content),
|
||||
@@ -242,6 +242,10 @@ class _MyPageState extends State<MyPage> {
|
||||
|
||||
Widget _bottomNav(AppLocalizations l10n) {
|
||||
return AppBottomNav(
|
||||
centerAction: AppBottomNavCenterAction(
|
||||
label: l10n.createTab,
|
||||
onTap: () => _act(MyPageAction.create),
|
||||
),
|
||||
items: [
|
||||
AppBottomNavItem(
|
||||
tabKey: const Key('mine-nav-home'),
|
||||
|
||||
@@ -101,7 +101,7 @@ class ContinueWatchingCard extends StatelessWidget {
|
||||
key: progressKey,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(color: Color(0xFFBBBBBB), fontSize: 9),
|
||||
style: const TextStyle(color: AppColors.muted, fontSize: 9),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -46,12 +46,12 @@ class MineHeader extends StatelessWidget {
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [Color(0xFF6A5CFF), AppColors.blue],
|
||||
colors: [AppColors.secondary, AppColors.blue],
|
||||
),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.person_rounded,
|
||||
color: AppColors.onSurface,
|
||||
color: AppColors.onPrimary,
|
||||
size: 22,
|
||||
),
|
||||
);
|
||||
@@ -76,7 +76,7 @@ class MineHeader extends StatelessWidget {
|
||||
subtitle,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(color: Color(0xFFBBBBBB), fontSize: 10),
|
||||
style: const TextStyle(color: AppColors.muted, fontSize: 10),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -44,7 +44,7 @@ class _NoticesPageState extends State<NoticesPage> {
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return Theme(
|
||||
data: AppTheme.dark(),
|
||||
data: AppTheme.light(),
|
||||
child: Scaffold(
|
||||
key: const Key('notices-page'),
|
||||
backgroundColor: AppColors.ink,
|
||||
|
||||
@@ -669,7 +669,7 @@ class PlayerLogic extends ChangeNotifier {
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: Color(0xFFB7B3B8),
|
||||
color: AppColors.muted,
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
|
||||
@@ -146,9 +146,9 @@ class _PlayerPageState extends State<PlayerPage> with WidgetsBindingObserver {
|
||||
),
|
||||
);
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle.light,
|
||||
value: SystemUiOverlayStyle.dark,
|
||||
child: Theme(
|
||||
data: AppTheme.dark(),
|
||||
data: AppTheme.light(),
|
||||
child: widget.embedded
|
||||
? content
|
||||
: Scaffold(backgroundColor: AppColors.ink, body: content),
|
||||
@@ -1155,7 +1155,7 @@ class _TopAction extends StatelessWidget {
|
||||
onPressed: onPressed,
|
||||
padding: EdgeInsets.zero,
|
||||
style: IconButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF2C2D33),
|
||||
backgroundColor: AppColors.card.withValues(alpha: 0.94),
|
||||
foregroundColor: AppColors.onSurface,
|
||||
),
|
||||
icon: Icon(icon, size: 18),
|
||||
@@ -1179,7 +1179,7 @@ class _PlayerAction extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Material(
|
||||
color: const Color(0xFF2A2A30),
|
||||
color: AppColors.card.withValues(alpha: 0.94),
|
||||
borderRadius: BorderRadius.circular(9),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: InkWell(
|
||||
|
||||
@@ -160,12 +160,7 @@ class HomeFeedOverlay extends StatelessWidget {
|
||||
radius: 14,
|
||||
blur: 6,
|
||||
padding: const EdgeInsets.all(12),
|
||||
gradient: const LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [Color(0xBF0F0F14), Color(0xA60F0F14)],
|
||||
),
|
||||
borderColor: Colors.white.withValues(alpha: 0.06),
|
||||
borderColor: AppColors.border,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -184,13 +179,13 @@ class HomeFeedOverlay extends StatelessWidget {
|
||||
if (drama.category.isNotEmpty && drama.category != genre)
|
||||
_tag(
|
||||
drama.category,
|
||||
background: const Color(0xFF333333),
|
||||
foreground: const Color(0xFFDDDDDD),
|
||||
background: AppColors.raised,
|
||||
foreground: AppColors.onSurface,
|
||||
),
|
||||
Text(
|
||||
l10n.episodeOfTotal(episode.number, drama.episodeCount),
|
||||
key: const Key('home-feed-episode'),
|
||||
style: const TextStyle(color: Color(0xFFBBBBBB), fontSize: 9),
|
||||
style: const TextStyle(color: AppColors.muted, fontSize: 9),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -248,7 +243,7 @@ class HomeFeedOverlay extends StatelessWidget {
|
||||
key: const Key('home-feed-episodes'),
|
||||
onPressed: onEpisodes,
|
||||
style: FilledButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF2A2A30),
|
||||
backgroundColor: AppColors.raised,
|
||||
foregroundColor: AppColors.onSurface,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
@@ -362,7 +357,7 @@ class _RoundIcon extends StatelessWidget {
|
||||
onPressed: onPressed,
|
||||
padding: EdgeInsets.zero,
|
||||
style: IconButton.styleFrom(
|
||||
backgroundColor: const Color(0xCC2C2D33),
|
||||
backgroundColor: AppColors.card.withValues(alpha: 0.94),
|
||||
foregroundColor: AppColors.onSurface,
|
||||
),
|
||||
icon: Icon(icon, size: 18),
|
||||
|
||||
@@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../core/theme/app_colors.dart';
|
||||
|
||||
/// Shared play/pause control used by the home feed and full-screen player.
|
||||
/// 首页沉浸流与全屏播放器共用的播放/暂停按钮。
|
||||
class PlayerCenterToggle extends StatelessWidget {
|
||||
const PlayerCenterToggle({
|
||||
super.key,
|
||||
@@ -26,7 +26,7 @@ class PlayerCenterToggle extends StatelessWidget {
|
||||
width: 52,
|
||||
height: 52,
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0x80000000),
|
||||
color: AppColors.blue,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
|
||||
@@ -117,7 +117,7 @@ class _PlayerFeaturedCommentState extends State<PlayerFeaturedComment> {
|
||||
Text(
|
||||
'· $time',
|
||||
style: const TextStyle(
|
||||
color: Color(0xFF777777),
|
||||
color: AppColors.muted,
|
||||
fontSize: 9,
|
||||
),
|
||||
),
|
||||
@@ -133,7 +133,7 @@ class _PlayerFeaturedCommentState extends State<PlayerFeaturedComment> {
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(
|
||||
color: Color(0xFFDDDDDD),
|
||||
color: AppColors.onSurface,
|
||||
fontSize: 10,
|
||||
height: 1.5,
|
||||
),
|
||||
|
||||
@@ -127,10 +127,8 @@ class _SeekProgressBarState extends State<SeekProgressBar> {
|
||||
? (scrubbing ? 3 : 1.5)
|
||||
: (scrubbing ? 4 : 3),
|
||||
activeTrackColor: AppColors.blue,
|
||||
inactiveTrackColor: widget.compact
|
||||
? Colors.white.withValues(alpha: 0.18)
|
||||
: const Color(0xFF474248),
|
||||
thumbColor: widget.compact ? AppColors.blue : Colors.white,
|
||||
inactiveTrackColor: AppColors.border,
|
||||
thumbColor: AppColors.onPrimary,
|
||||
thumbShape: RoundSliderThumbShape(
|
||||
enabledThumbRadius: widget.compact
|
||||
? (scrubbing ? 6 : 4)
|
||||
|
||||
@@ -22,7 +22,7 @@ class SettingsPage extends StatelessWidget {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final auth = context.watch<AuthController>();
|
||||
return Theme(
|
||||
data: AppTheme.dark(),
|
||||
data: AppTheme.light(),
|
||||
child: Scaffold(
|
||||
key: const Key('settings-page'),
|
||||
backgroundColor: AppColors.ink,
|
||||
|
||||
@@ -56,7 +56,7 @@ class _StorePageState extends State<StorePage> {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final isVip = widget.type == StoreController.vipType;
|
||||
return Theme(
|
||||
data: AppTheme.dark(),
|
||||
data: AppTheme.light(),
|
||||
child: Scaffold(
|
||||
key: const Key('store-page'),
|
||||
backgroundColor: AppColors.ink,
|
||||
|
||||
@@ -44,7 +44,7 @@ class _WalletPageState extends State<WalletPage> {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final wallet = context.watch<WalletController>();
|
||||
return Theme(
|
||||
data: AppTheme.dark(),
|
||||
data: AppTheme.light(),
|
||||
child: Scaffold(
|
||||
key: const Key('wallet-page'),
|
||||
backgroundColor: AppColors.ink,
|
||||
@@ -188,7 +188,7 @@ class _BalanceHero extends StatelessWidget {
|
||||
gradient: const LinearGradient(
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
colors: [Color(0xFF2B2116), Color(0xFF17171D)],
|
||||
colors: [AppColors.goldCard, AppColors.card],
|
||||
),
|
||||
border: Border.all(color: AppColors.gold.withValues(alpha: 0.35)),
|
||||
boxShadow: [
|
||||
|
||||
@@ -33,7 +33,7 @@ class WatchRecordsPage extends StatelessWidget {
|
||||
final signedIn = context.watch<AuthController>().isSignedIn;
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return Theme(
|
||||
data: AppTheme.dark(),
|
||||
data: AppTheme.light(),
|
||||
child: Scaffold(
|
||||
key: const Key('watch-records-page'),
|
||||
backgroundColor: AppColors.ink,
|
||||
|
||||
Reference in new issue
Block a user