fix(ui): 打磨推荐追剧我的设置页间距与图标
This commit is contained in:
1 parent
de7da64886
commit
5346be40a9
33 files changed
+1408
-811
No files matched your search
+84
-146
@@ -6,39 +6,33 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../core/data/models/drama.dart';
|
||||
import '../../core/data/models/watch_progress.dart';
|
||||
import '../../core/data/repositories/watch_history_repository.dart';
|
||||
import '../../core/data/services/auth_controller.dart';
|
||||
import '../../core/data/services/catalog_controller.dart';
|
||||
import '../../core/data/services/favorite_controller.dart';
|
||||
import '../../core/data/services/locale_controller.dart';
|
||||
import '../../core/data/services/wallet_controller.dart';
|
||||
import '../../core/theme/app_colors.dart';
|
||||
import '../../core/theme/app_dimens.dart';
|
||||
import '../../core/theme/app_theme.dart';
|
||||
import '../../core/widgets/app_glow_panel.dart';
|
||||
import '../../core/widgets/app_root_tab.dart';
|
||||
import '../../core/widgets/auth_gate.dart';
|
||||
import '../../core/widgets/plain_page_scaffold.dart';
|
||||
import '../../l10n/app_localizations.dart';
|
||||
import '../downloads/downloads_page.dart';
|
||||
import '../account/account_profile_page.dart';
|
||||
import '../favorites/favorites_page.dart';
|
||||
import '../filter/filter_page.dart';
|
||||
import '../notices/notices_page.dart';
|
||||
import '../player/open_player.dart';
|
||||
import '../settings/settings_page.dart';
|
||||
import '../store/vip_page.dart';
|
||||
import '../wallet/wallet_page.dart';
|
||||
import '../watch_records/watch_records_page.dart';
|
||||
import 'about_page.dart';
|
||||
import 'mine_binding.dart';
|
||||
import 'mine_logic.dart';
|
||||
import 'mine_types.dart';
|
||||
import 'widgets/mine_continue_watching.dart';
|
||||
import 'widgets/mine_header.dart';
|
||||
import 'widgets/mine_menu.dart';
|
||||
import 'widgets/mine_more_services.dart';
|
||||
import 'widgets/mine_stats_panel.dart';
|
||||
|
||||
/// K28-B 我的页。
|
||||
class MyPage extends StatefulWidget {
|
||||
@@ -136,41 +130,27 @@ class _MyPageState extends State<MyPage> {
|
||||
Widget _page(BuildContext context) {
|
||||
final content = DecoratedBox(
|
||||
key: const Key('mine-page-surface'),
|
||||
// 与追剧页同款:纯黑底 + 顶部暗红光晕。
|
||||
decoration: const BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
AppColors.mineGradientTop,
|
||||
AppColors.mineGradientMiddle,
|
||||
AppColors.mineGradientBottom,
|
||||
AppColors.followingGlow,
|
||||
AppColors.followingGlowMid,
|
||||
AppColors.appBackground,
|
||||
],
|
||||
stops: [0, 0.4, 0.75],
|
||||
stops: [0, 0.14, 0.3],
|
||||
),
|
||||
),
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
const DecoratedBox(
|
||||
key: Key('mine-page-glow'),
|
||||
decoration: BoxDecoration(
|
||||
gradient: RadialGradient(
|
||||
center: Alignment(0, -0.95),
|
||||
radius: 0.9,
|
||||
colors: [AppColors.mineGradientGlow, AppColors.transparent],
|
||||
),
|
||||
),
|
||||
),
|
||||
SafeArea(
|
||||
bottom: false,
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(child: _body(context)),
|
||||
if (!embedded) _bottomNav(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
child: SafeArea(
|
||||
bottom: false,
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(child: _body(context)),
|
||||
if (!embedded) _bottomNav(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
@@ -185,22 +165,7 @@ class _MyPageState extends State<MyPage> {
|
||||
}
|
||||
|
||||
Widget _body(BuildContext context) {
|
||||
final auth = context.watch<AuthController>();
|
||||
final favorites = context.watch<FavoriteController>();
|
||||
final wallet = context.watch<WalletController>();
|
||||
final continueWatching = logic.recent.take(10).toList(growable: false);
|
||||
final followingCount =
|
||||
favorites.error == null && !(favorites.loading && favorites.total == 0)
|
||||
? favorites.total
|
||||
: null;
|
||||
final watchRecordCount =
|
||||
logic.recentError == null &&
|
||||
!(logic.recentLoading && logic.watchRecordTotal == null)
|
||||
? logic.watchRecordTotal
|
||||
: null;
|
||||
final coinBalance = auth.isSignedIn && wallet.snapshot != null
|
||||
? wallet.balance
|
||||
: null;
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return ListView(
|
||||
key: const Key('mine-page-scroll'),
|
||||
padding: const EdgeInsets.only(bottom: AppDimens.spaceXl),
|
||||
@@ -214,6 +179,7 @@ class _MyPageState extends State<MyPage> {
|
||||
onEdit: () => _push(const AccountProfilePage()),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: AppDimens.spaceMd),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: AppDimens.pageHorizontal,
|
||||
@@ -222,23 +188,16 @@ class _MyPageState extends State<MyPage> {
|
||||
onOpen: () => _openDestination(MineDestination.vip),
|
||||
),
|
||||
),
|
||||
if (continueWatching.isNotEmpty) ...[
|
||||
const SizedBox(height: AppDimens.mineSectionGap),
|
||||
MineContinueWatching(
|
||||
records: continueWatching,
|
||||
onOpenRecord: _openContinueRecord,
|
||||
onOpenAll: _openHistoryTab,
|
||||
),
|
||||
],
|
||||
const SizedBox(height: AppDimens.mineSectionGap),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: AppDimens.mineGridHorizontal,
|
||||
horizontal: AppDimens.pageHorizontal,
|
||||
),
|
||||
child: MineStatsPanel(
|
||||
followingCount: followingCount,
|
||||
watchRecordCount: watchRecordCount,
|
||||
coinBalance: coinBalance,
|
||||
child: MineQuickActions(
|
||||
onWallet: () => _openDestination(MineDestination.wallet),
|
||||
onFavorites: () => _push(const FavoritesPage()),
|
||||
onDownloads: () => _openDestination(MineDestination.downloads),
|
||||
onHistory: () => _openDestination(MineDestination.history),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: AppDimens.mineSectionGap),
|
||||
@@ -246,25 +205,40 @@ class _MyPageState extends State<MyPage> {
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: AppDimens.mineGridHorizontal,
|
||||
),
|
||||
child: MineMenuList(
|
||||
onOpen: _openDestination,
|
||||
onLanguage: _openLanguage,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: AppDimens.mineSectionGap),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: AppDimens.mineGridHorizontal,
|
||||
),
|
||||
child: MineMoreServices(
|
||||
onCommonQuestions: _pushPlaceholder,
|
||||
onAbout: () => _push(const MineAboutPage()),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
l10n.moreServices,
|
||||
style: const TextStyle(
|
||||
color: AppColors.textTertiary,
|
||||
fontSize: AppDimens.mineSectionTitle,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: AppDimens.spaceSm),
|
||||
MineServiceList(
|
||||
onOpen: _openDestination,
|
||||
onLanguage: _openLanguage,
|
||||
languageName: _languageName(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// 语言设置行右侧展示的当前语言名。
|
||||
String _languageName(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final code = context.read<LocaleController>().locale?.languageCode;
|
||||
return switch (code) {
|
||||
'en' => l10n.english,
|
||||
'id' => l10n.bahasaIndonesia,
|
||||
_ => l10n.simplifiedChinese,
|
||||
};
|
||||
}
|
||||
|
||||
void _openDestination(MineDestination destination) {
|
||||
switch (destination) {
|
||||
case MineDestination.history:
|
||||
@@ -290,45 +264,6 @@ class _MyPageState extends State<MyPage> {
|
||||
unawaited(openAuthPage(context));
|
||||
}
|
||||
|
||||
void _openHistoryTab() {
|
||||
final callback = widget.callbacks.onOpenHistoryTab;
|
||||
if (callback != null) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
unawaited(_openHistoryPage());
|
||||
}
|
||||
|
||||
/// 继续观看卡片:补齐剧集后直接进全屏播放页,播放器自己会定位到记录的秒数。
|
||||
Future<void> _openContinueRecord(WatchProgress record) async {
|
||||
final catalog = context.read<CatalogController>();
|
||||
// 续看记录只有剧的概要信息,先拼一个占位对象让目录去取完整详情
|
||||
final summary = Drama(
|
||||
id: record.dramaId,
|
||||
title: record.dramaTitle ?? '',
|
||||
synopsis: '',
|
||||
posterUrl: record.dramaCover ?? '',
|
||||
);
|
||||
Drama drama;
|
||||
try {
|
||||
drama = await catalog.requireDetail(summary);
|
||||
} catch (_) {
|
||||
if (!mounted) return;
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(SnackBar(content: Text(l10n.detailLoadFailed)));
|
||||
return;
|
||||
}
|
||||
if (!mounted) return;
|
||||
await playDramaFromCatalog(
|
||||
context,
|
||||
drama,
|
||||
episodeId: record.episodeId.isEmpty ? null : record.episodeId,
|
||||
);
|
||||
if (mounted) unawaited(logic.refreshRecent());
|
||||
}
|
||||
|
||||
Future<void> _openHistoryPage() async {
|
||||
await _push(const WatchRecordsPage());
|
||||
if (mounted) unawaited(logic.refreshRecent());
|
||||
@@ -341,7 +276,25 @@ class _MyPageState extends State<MyPage> {
|
||||
}
|
||||
|
||||
void _pushPlaceholder() {
|
||||
unawaited(_push(const _MinePlaceholderPage()));
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
unawaited(
|
||||
_push(
|
||||
PlainPageScaffold(
|
||||
pageKey: const Key('mine-placeholder-page'),
|
||||
backKey: const Key('mine-placeholder-back'),
|
||||
title: l10n.contactSupport,
|
||||
child: Center(
|
||||
child: Text(
|
||||
l10n.comingSoon,
|
||||
style: const TextStyle(
|
||||
color: AppColors.textSecondary,
|
||||
fontSize: AppDimens.body,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _openProtected(Widget page) async {
|
||||
@@ -410,14 +363,16 @@ class _LanguageSheet extends StatelessWidget {
|
||||
(const Locale('en'), const Key('mine-language-en'), l10n.english),
|
||||
(const Locale('id'), const Key('mine-language-id'), l10n.bahasaIndonesia),
|
||||
];
|
||||
return Material(
|
||||
key: const Key('mine-language-sheet'),
|
||||
color: AppColors.contentCard,
|
||||
return AppGlowPanel(
|
||||
borderRadius: const BorderRadius.vertical(
|
||||
top: Radius.circular(AppDimens.mineCardRadius),
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: SafeArea(
|
||||
border: false,
|
||||
child: Material(
|
||||
key: const Key('mine-language-sheet'),
|
||||
type: MaterialType.transparency,
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: SafeArea(
|
||||
top: false,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(20, 14, 20, 20),
|
||||
@@ -440,7 +395,13 @@ class _LanguageSheet extends StatelessWidget {
|
||||
IconButton(
|
||||
tooltip: l10n.close,
|
||||
onPressed: () => Navigator.pop(context),
|
||||
icon: const Icon(Icons.close_rounded),
|
||||
visualDensity: VisualDensity.compact,
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(
|
||||
minWidth: 32,
|
||||
minHeight: 32,
|
||||
),
|
||||
icon: const Icon(Icons.close_rounded, size: 20),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -461,29 +422,6 @@ class _LanguageSheet extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _MinePlaceholderPage extends StatelessWidget {
|
||||
const _MinePlaceholderPage();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final title = l10n.helpFeedback;
|
||||
return PlainPageScaffold(
|
||||
pageKey: const Key('mine-placeholder-page'),
|
||||
backKey: const Key('mine-placeholder-back'),
|
||||
title: title,
|
||||
child: Center(
|
||||
child: Text(
|
||||
l10n.comingSoon,
|
||||
style: const TextStyle(
|
||||
color: AppColors.textSecondary,
|
||||
fontSize: AppDimens.body,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user