feat: 逻辑与页面布局分离
This commit is contained in:
1 parent
b1f6ce4bf9
commit
1e61ae7a0b
11 files changed
+1233
-907
No files matched your search
@@ -1,8 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../core/data/models/drama.dart';
|
||||
import '../discover/discover_logic.dart';
|
||||
import '../drama_detail/drama_detail_view.dart';
|
||||
import '../mine/mine_logic.dart';
|
||||
|
||||
class HomeLogic {
|
||||
class HomeLogic extends ChangeNotifier {
|
||||
HomeLogic(List<Drama> dramas) : currentDrama = dramas.first;
|
||||
|
||||
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
@@ -16,6 +19,11 @@ class HomeLogic {
|
||||
bool drawerOpen = false;
|
||||
bool detailOpen = false;
|
||||
bool videoImmersive = false;
|
||||
bool _disposed = false;
|
||||
|
||||
void notify() {
|
||||
if (!_disposed) notifyListeners();
|
||||
}
|
||||
|
||||
void select(
|
||||
int nextTab, {
|
||||
@@ -32,5 +40,105 @@ class HomeLogic {
|
||||
sectionRequest++;
|
||||
}
|
||||
if (resume) resumeRequest++;
|
||||
notify();
|
||||
}
|
||||
|
||||
void openMenu() {
|
||||
drawerOpen = true;
|
||||
notify();
|
||||
scaffoldKey.currentState?.openDrawer();
|
||||
}
|
||||
|
||||
void selectFromMenu(int nextTab, {int? mySection}) {
|
||||
scaffoldKey.currentState?.closeDrawer();
|
||||
select(nextTab, mySection: mySection);
|
||||
}
|
||||
|
||||
Future<void> openCurrentSeries(BuildContext context) async {
|
||||
detailOpen = true;
|
||||
notify();
|
||||
scaffoldKey.currentState?.closeDrawer();
|
||||
await WidgetsBinding.instance.endOfFrame;
|
||||
if (!context.mounted) return;
|
||||
try {
|
||||
await Navigator.of(context).push<void>(
|
||||
MaterialPageRoute(
|
||||
builder: (_) => DramaDetailPage(drama: currentDrama),
|
||||
),
|
||||
);
|
||||
} finally {
|
||||
if (context.mounted) {
|
||||
detailOpen = false;
|
||||
notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void openDrama(BuildContext context, Drama drama) {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute<void>(builder: (_) => DramaDetailPage(drama: drama)),
|
||||
);
|
||||
}
|
||||
|
||||
void discoverAction(BuildContext context, DiscoverPageAction action) {
|
||||
switch (action) {
|
||||
case DiscoverPageAction.home:
|
||||
select(0);
|
||||
case DiscoverPageAction.my:
|
||||
select(2);
|
||||
case DiscoverPageAction.watchlist:
|
||||
select(2, watchlist: true);
|
||||
case DiscoverPageAction.resume:
|
||||
select(0, resume: true);
|
||||
case DiscoverPageAction.detail:
|
||||
openDrama(context, currentDrama);
|
||||
}
|
||||
}
|
||||
|
||||
void myAction(MyPageAction action) {
|
||||
switch (action) {
|
||||
case MyPageAction.home:
|
||||
select(0);
|
||||
case MyPageAction.discover:
|
||||
select(1, search: true);
|
||||
case MyPageAction.resume:
|
||||
select(0, resume: true);
|
||||
}
|
||||
}
|
||||
|
||||
void onSystemBack() {
|
||||
if (drawerOpen) {
|
||||
scaffoldKey.currentState?.closeDrawer();
|
||||
} else if (videoImmersive) {
|
||||
backRequest++;
|
||||
notify();
|
||||
} else if (tab != 0) {
|
||||
select(0);
|
||||
} else {
|
||||
backRequest++;
|
||||
notify();
|
||||
}
|
||||
}
|
||||
|
||||
void onDrawerChanged(bool opened) {
|
||||
if (drawerOpen == opened) return;
|
||||
drawerOpen = opened;
|
||||
notify();
|
||||
}
|
||||
|
||||
void onDramaChanged(Drama drama) {
|
||||
currentDrama = drama;
|
||||
notify();
|
||||
}
|
||||
|
||||
void onImmersiveChanged(bool value) {
|
||||
videoImmersive = value;
|
||||
notify();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_disposed = true;
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
+31
-115
@@ -5,7 +5,6 @@ import '../../core/data/models/drama.dart';
|
||||
import '../../core/data/services/catalog_controller.dart';
|
||||
import '../../l10n/app_localizations.dart';
|
||||
import '../discover/discover_view.dart';
|
||||
import '../drama_detail/drama_detail_view.dart';
|
||||
import '../mine/mine_view.dart';
|
||||
import '../player/player_view.dart';
|
||||
import 'home_binding.dart';
|
||||
@@ -79,163 +78,80 @@ class _HomeTabsState extends State<_HomeTabs> {
|
||||
logic = HomeBinding().create(widget.dramas);
|
||||
}
|
||||
|
||||
void _select(
|
||||
int tab, {
|
||||
bool search = false,
|
||||
bool watchlist = false,
|
||||
bool resume = false,
|
||||
int? mySection,
|
||||
}) {
|
||||
setState(
|
||||
() => logic.select(
|
||||
tab,
|
||||
search: search,
|
||||
watchlist: watchlist,
|
||||
resume: resume,
|
||||
mySection: mySection,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _openMenu() {
|
||||
setState(() => logic.drawerOpen = true);
|
||||
logic.scaffoldKey.currentState?.openDrawer();
|
||||
}
|
||||
|
||||
void _selectFromMenu(int tab, {int? mySection}) {
|
||||
logic.scaffoldKey.currentState?.closeDrawer();
|
||||
_select(tab, mySection: mySection);
|
||||
}
|
||||
|
||||
Future<void> _openCurrentSeries() async {
|
||||
setState(() => logic.detailOpen = true);
|
||||
logic.scaffoldKey.currentState?.closeDrawer();
|
||||
await WidgetsBinding.instance.endOfFrame;
|
||||
if (!mounted) return;
|
||||
try {
|
||||
await Navigator.of(context).push<void>(
|
||||
MaterialPageRoute(
|
||||
builder: (_) => DramaDetailPage(drama: logic.currentDrama),
|
||||
),
|
||||
);
|
||||
} finally {
|
||||
if (mounted) setState(() => logic.detailOpen = false);
|
||||
}
|
||||
}
|
||||
|
||||
void _discoverAction(DiscoverPageAction action) {
|
||||
switch (action) {
|
||||
case DiscoverPageAction.home:
|
||||
_select(0);
|
||||
case DiscoverPageAction.my:
|
||||
_select(2);
|
||||
case DiscoverPageAction.watchlist:
|
||||
_select(2, watchlist: true);
|
||||
case DiscoverPageAction.resume:
|
||||
_select(0, resume: true);
|
||||
case DiscoverPageAction.detail:
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (_) => DramaDetailPage(drama: logic.currentDrama),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _myAction(MyPageAction action) {
|
||||
switch (action) {
|
||||
case MyPageAction.home:
|
||||
_select(0);
|
||||
case MyPageAction.discover:
|
||||
_select(1, search: true);
|
||||
case MyPageAction.resume:
|
||||
_select(0, resume: true);
|
||||
}
|
||||
@override
|
||||
void dispose() {
|
||||
logic.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListenableBuilder(
|
||||
listenable: logic,
|
||||
builder: (context, _) => _scaffold(context),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _scaffold(BuildContext context) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return PopScope(
|
||||
canPop: false,
|
||||
onPopInvokedWithResult: (didPop, _) {
|
||||
if (didPop) return;
|
||||
if (logic.drawerOpen) {
|
||||
logic.scaffoldKey.currentState?.closeDrawer();
|
||||
} else if (logic.videoImmersive) {
|
||||
setState(() => logic.backRequest++);
|
||||
} else if (logic.tab != 0) {
|
||||
_select(0);
|
||||
} else {
|
||||
setState(() => logic.backRequest++);
|
||||
}
|
||||
logic.onSystemBack();
|
||||
},
|
||||
child: Scaffold(
|
||||
key: logic.scaffoldKey,
|
||||
backgroundColor: const Color(0xFF0B0C10),
|
||||
drawer: HomeQuickDrawer(
|
||||
drama: logic.currentDrama,
|
||||
onOpenSeries: _openCurrentSeries,
|
||||
onDiscover: () => _selectFromMenu(1),
|
||||
onHistory: () => _selectFromMenu(2, mySection: 0),
|
||||
onWatchlist: () => _selectFromMenu(2, mySection: 1),
|
||||
onLiked: () => _selectFromMenu(2, mySection: 2),
|
||||
onOpenSeries: () => logic.openCurrentSeries(context),
|
||||
onDiscover: () => logic.selectFromMenu(1),
|
||||
onHistory: () => logic.selectFromMenu(2, mySection: 0),
|
||||
onWatchlist: () => logic.selectFromMenu(2, mySection: 1),
|
||||
onLiked: () => logic.selectFromMenu(2, mySection: 2),
|
||||
),
|
||||
drawerEnableOpenDragGesture: false,
|
||||
onDrawerChanged: (opened) {
|
||||
if (logic.drawerOpen != opened) {
|
||||
setState(() => logic.drawerOpen = opened);
|
||||
}
|
||||
},
|
||||
onDrawerChanged: logic.onDrawerChanged,
|
||||
body: IndexedStack(
|
||||
index: logic.tab,
|
||||
children: [
|
||||
PlayerPage(
|
||||
drama: widget.dramas.first,
|
||||
feedDramas: widget.dramas,
|
||||
onDramaChanged: (drama) =>
|
||||
setState(() => logic.currentDrama = drama),
|
||||
onDramaChanged: logic.onDramaChanged,
|
||||
initialIndex: 0,
|
||||
homeMode: true,
|
||||
embedded: true,
|
||||
active: logic.tab == 0 && !logic.drawerOpen && !logic.detailOpen,
|
||||
resumeRequest: logic.resumeRequest,
|
||||
backRequest: logic.backRequest,
|
||||
onDiscover: () => _select(1),
|
||||
onMy: () => _select(2),
|
||||
onSearch: () => _select(1, search: true),
|
||||
onMenu: _openMenu,
|
||||
onImmersiveChanged: (value) =>
|
||||
setState(() => logic.videoImmersive = value),
|
||||
onDiscover: () => logic.select(1),
|
||||
onMy: () => logic.select(2),
|
||||
onSearch: () => logic.select(1, search: true),
|
||||
onMenu: logic.openMenu,
|
||||
onImmersiveChanged: logic.onImmersiveChanged,
|
||||
),
|
||||
DiscoverPage(
|
||||
drama: logic.currentDrama,
|
||||
dramas: widget.dramas,
|
||||
onDramaSelected: (drama) => Navigator.of(context).push(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (_) => DramaDetailPage(drama: drama),
|
||||
),
|
||||
),
|
||||
onDramaSelected: (drama) => logic.openDrama(context, drama),
|
||||
duration: Duration.zero,
|
||||
embedded: true,
|
||||
active: logic.tab == 1,
|
||||
searchRequest: logic.searchRequest,
|
||||
onAction: _discoverAction,
|
||||
onAction: (action) => logic.discoverAction(context, action),
|
||||
),
|
||||
MyPage(
|
||||
drama: logic.currentDrama,
|
||||
dramas: widget.dramas,
|
||||
onDramaSelected: (drama) => Navigator.of(context).push(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (_) => DramaDetailPage(drama: drama),
|
||||
),
|
||||
),
|
||||
onDramaSelected: (drama) => logic.openDrama(context, drama),
|
||||
duration: Duration.zero,
|
||||
initialSection: logic.mySection,
|
||||
sectionRequest: logic.sectionRequest,
|
||||
embedded: true,
|
||||
active: logic.tab == 2,
|
||||
onAction: _myAction,
|
||||
onAction: logic.myAction,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -258,21 +174,21 @@ class _HomeTabsState extends State<_HomeTabs> {
|
||||
icon: Icons.play_circle_outline_rounded,
|
||||
label: l10n.homeTab,
|
||||
selected: logic.tab == 0,
|
||||
onTap: () => _select(0),
|
||||
onTap: () => logic.select(0),
|
||||
),
|
||||
_TabButton(
|
||||
key: const Key('tab-discover'),
|
||||
icon: Icons.explore_outlined,
|
||||
label: l10n.discoverTab,
|
||||
selected: logic.tab == 1,
|
||||
onTap: () => _select(1),
|
||||
onTap: () => logic.select(1),
|
||||
),
|
||||
_TabButton(
|
||||
key: const Key('tab-my'),
|
||||
icon: Icons.video_library_outlined,
|
||||
label: l10n.myTab,
|
||||
selected: logic.tab == 2,
|
||||
onTap: () => _select(2),
|
||||
onTap: () => logic.select(2),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
Reference in new issue
Block a user