feat: 逻辑与页面布局分离
This commit is contained in:
1 parent
b1f6ce4bf9
commit
1e61ae7a0b
11 files changed
+1233
-907
No files matched your search
@@ -1,19 +1,47 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../core/data/models/drama.dart';
|
||||
import '../../core/data/repositories/watch_history_repository.dart';
|
||||
import '../player/player_view.dart';
|
||||
|
||||
class DramaDetailLogic {
|
||||
class DramaDetailLogic extends ChangeNotifier {
|
||||
DramaDetailLogic({required this.drama, required this.history});
|
||||
|
||||
final Drama drama;
|
||||
final WatchHistoryRepository history;
|
||||
int? continueIndex;
|
||||
bool _disposed = false;
|
||||
|
||||
void notify() {
|
||||
if (!_disposed) notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> loadContinue() async {
|
||||
final id = await history.lastEpisodeId(demoProfileId, drama.id);
|
||||
if (id == null) return;
|
||||
final index = drama.episodes.indexWhere((episode) => episode.id == id);
|
||||
if (index >= 0 && drama.episodes[index].isFree) {
|
||||
continueIndex = index;
|
||||
try {
|
||||
final id = await history.lastEpisodeId(demoProfileId, drama.id);
|
||||
if (id == null || _disposed) return;
|
||||
final index = drama.episodes.indexWhere((episode) => episode.id == id);
|
||||
if (index >= 0 && drama.episodes[index].isFree) {
|
||||
continueIndex = index;
|
||||
notify();
|
||||
}
|
||||
} catch (_) {
|
||||
// Keep the first episode available if preferences cannot be read.
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> openPlayer(BuildContext context, int index) async {
|
||||
await Navigator.of(context).push(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (_) => PlayerPage(drama: drama, initialIndex: index),
|
||||
),
|
||||
);
|
||||
await loadContinue();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_disposed = true;
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
|
||||
import '../../core/data/models/drama.dart';
|
||||
import '../../core/formatting/localized_content.dart';
|
||||
import '../../l10n/app_localizations.dart';
|
||||
import '../player/player_view.dart';
|
||||
import 'drama_detail_binding.dart';
|
||||
import 'drama_detail_logic.dart';
|
||||
|
||||
@@ -22,29 +21,24 @@ class _DramaDetailPageState extends State<DramaDetailPage> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
logic = DramaDetailBinding().create(drama: widget.drama);
|
||||
_loadContinue();
|
||||
logic.loadContinue();
|
||||
}
|
||||
|
||||
Future<void> _loadContinue() async {
|
||||
try {
|
||||
await logic.loadContinue();
|
||||
if (mounted) setState(() {});
|
||||
} catch (_) {
|
||||
// Keep the first episode available if preferences cannot be read.
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _openPlayer(BuildContext context, int index) async {
|
||||
await Navigator.of(context).push(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (_) => PlayerPage(drama: logic.drama, initialIndex: index),
|
||||
),
|
||||
);
|
||||
await _loadContinue();
|
||||
@override
|
||||
void dispose() {
|
||||
logic.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListenableBuilder(
|
||||
listenable: logic,
|
||||
builder: (context, _) => _page(context),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _page(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final drama = logic.drama;
|
||||
return Scaffold(
|
||||
@@ -87,7 +81,8 @@ class _DramaDetailPageState extends State<DramaDetailPage> {
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
FilledButton.icon(
|
||||
onPressed: () => _openPlayer(context, logic.continueIndex ?? 0),
|
||||
onPressed: () =>
|
||||
logic.openPlayer(context, logic.continueIndex ?? 0),
|
||||
icon: const Icon(Icons.play_arrow_rounded),
|
||||
label: Text(
|
||||
logic.continueIndex == null
|
||||
@@ -124,7 +119,7 @@ class _DramaDetailPageState extends State<DramaDetailPage> {
|
||||
title: Text(l10n.episodeLabel(episode.number)),
|
||||
subtitle: Text(l10n.freeTestMedia),
|
||||
trailing: const Icon(Icons.play_circle_outline_rounded),
|
||||
onTap: () => _openPlayer(context, index),
|
||||
onTap: () => logic.openPlayer(context, index),
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user