feat(flutter): 接入分类记录收藏与下载授权

This commit is contained in:
Zhou Weidong committed 2026-10-17 14:49:16 +08:00
1 parent 00280ca0da
commit cc4d7c5a9d
52 files changed
+4440 -171

No files matched your search

+42 -3
View File
@@ -9,9 +9,7 @@ import '../theme/app_colors.dart';
/// 打开登录 / 注册页(沿用现有 Navigator 风格,不引路由库)
Future<void> openAuthPage(BuildContext context, {bool signUpMode = false}) {
return Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (_) => AuthPage(signUpMode: signUpMode),
),
MaterialPageRoute<void>(builder: (_) => AuthPage(signUpMode: signUpMode)),
);
}
@@ -81,3 +79,44 @@ Future<bool> ensureSignedIn(BuildContext context) async {
}
return false;
}
/// 页面级登录引导,用于记录、收藏和下载等必须登录的独立页面。
class AuthGatePanel extends StatelessWidget {
const AuthGatePanel({super.key});
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Center(
key: const Key('auth-gate-panel'),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 32),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
l10n.authGateTitle,
textAlign: TextAlign.center,
style: const TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.w800,
),
),
const SizedBox(height: 8),
Text(
l10n.authGateMessage,
textAlign: TextAlign.center,
style: const TextStyle(color: AppColors.muted, fontSize: 13),
),
const SizedBox(height: 18),
FilledButton(
onPressed: () => openAuthPage(context),
child: Text(l10n.authGateAction),
),
],
),
),
);
}
}
+29
View File
@@ -0,0 +1,29 @@
// Author: fruit.com.cn
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../l10n/app_localizations.dart';
import '../data/services/download_controller.dart';
import 'auth_gate.dart';
/// 详情页与播放页共用的下载授权入口。
///
/// 未登录先走登录闸;业务拒绝时直接展示后端 message。
Future<void> requestEpisodeDownload(
BuildContext context,
String episodeId,
) async {
if (!await ensureSignedIn(context)) return;
if (!context.mounted) return;
final result = await context.read<DownloadController>().grant(episodeId);
if (!context.mounted) return;
final l10n = AppLocalizations.of(context)!;
final hasBackendMessage = result.message?.trim().isNotEmpty ?? false;
final message = result.ok
? l10n.downloadGranted
: hasBackendMessage
? result.message!
: l10n.downloadGrantFailed;
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(message)));
}
+73
View File
@@ -0,0 +1,73 @@
// Author: fruit.com.cn
import 'package:flutter/material.dart';
import '../data/models/drama.dart';
import '../theme/app_colors.dart';
import 'remote_image.dart';
/// 收藏等账号列表复用的剧集卡片,视觉与"我的"页列表保持一致。
class LibraryDramaTile extends StatelessWidget {
const LibraryDramaTile({
super.key,
required this.drama,
required this.onTap,
this.trailing,
});
final Drama drama;
final VoidCallback? onTap;
final Widget? trailing;
@override
Widget build(BuildContext context) {
return Material(
color: const Color(0xFF1B1C21),
borderRadius: BorderRadius.circular(12),
clipBehavior: Clip.antiAlias,
child: InkWell(
onTap: onTap,
child: Padding(
padding: const EdgeInsets.all(9),
child: Row(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(8),
child: RemoteImage(drama.posterUrl, width: 74, height: 103),
),
const SizedBox(width: 11),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
drama.title,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: Colors.white,
fontSize: 15,
fontWeight: FontWeight.w700,
),
),
const SizedBox(height: 7),
Text(
drama.genre.isEmpty ? drama.category : drama.genre,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: AppColors.muted,
fontSize: 12,
),
),
],
),
),
?trailing,
],
),
),
),
);
}
}