pikapika/lib/screens/ComicInfoScreen.dart

372 lines
12 KiB
Dart
Raw Permalink Normal View History

2022-07-04 02:02:09 +00:00
import 'dart:async';
2021-09-29 23:57:09 +00:00
import 'package:flutter/material.dart';
2021-11-11 03:00:38 +00:00
import 'package:pikapika/basic/Common.dart';
import 'package:pikapika/basic/Cross.dart';
import 'package:pikapika/basic/Entities.dart';
2022-03-03 02:36:44 +00:00
import 'package:pikapika/basic/Method.dart';
2022-01-18 06:01:01 +00:00
import 'package:pikapika/basic/Navigator.dart';
2022-03-03 02:36:44 +00:00
import 'package:pikapika/screens/ComicsScreen.dart';
2021-11-11 03:00:38 +00:00
import 'package:pikapika/screens/components/CommentMainType.dart';
import 'package:pikapika/screens/components/ItemBuilder.dart';
2022-04-18 02:55:08 +00:00
import 'package:pikapika/screens/components/Recommendation.dart';
2022-03-03 02:36:44 +00:00
2023-01-31 10:50:51 +00:00
import '../basic/config/IconLoading.dart';
2021-09-29 23:57:09 +00:00
import 'ComicReaderScreen.dart';
import 'DownloadConfirmScreen.dart';
import 'components/ComicDescriptionCard.dart';
import 'components/ComicInfoCard.dart';
import 'components/ComicTagsCard.dart';
2022-03-03 02:36:44 +00:00
import 'components/CommentList.dart';
2021-09-29 23:57:09 +00:00
import 'components/ContentError.dart';
import 'components/ContentLoading.dart';
import 'components/ContinueReadButton.dart';
2023-05-08 09:57:28 +00:00
import 'components/ListView.dart';
2022-03-19 04:12:27 +00:00
import 'components/RightClickPop.dart';
2021-09-29 23:57:09 +00:00
// 漫画详情
class ComicInfoScreen extends StatefulWidget {
final String comicId;
2022-07-04 02:02:09 +00:00
final bool holdPkz;
2021-09-29 23:57:09 +00:00
2022-07-04 02:02:09 +00:00
const ComicInfoScreen({Key? key, required this.comicId, this.holdPkz = false})
: super(key: key);
2021-09-29 23:57:09 +00:00
@override
State<StatefulWidget> createState() => _ComicInfoScreenState();
}
class _ComicInfoScreenState extends State<ComicInfoScreen> with RouteAware {
late var _tabIndex = 0;
late Future<ComicInfo> _comicFuture = _loadComic();
2022-06-03 03:19:29 +00:00
late Key _comicFutureKey = UniqueKey();
2021-09-29 23:57:09 +00:00
late Future<ViewLog?> _viewFuture = _loadViewLog();
late Future<List<Ep>> _epListFuture = _loadEps();
2022-07-04 02:02:09 +00:00
StreamSubscription<String?>? _linkSubscription;
2021-09-29 23:57:09 +00:00
Future<ComicInfo> _loadComic() async {
return await method.comicInfo(widget.comicId);
}
Future<List<Ep>> _loadEps() async {
List<Ep> eps = [];
var page = 0;
late EpPage rsp;
do {
rsp = await method.comicEpPage(widget.comicId, ++page);
eps.addAll(rsp.docs);
} while (rsp.page < rsp.pages);
return eps;
}
Future<ViewLog?> _loadViewLog() {
return method.loadView(widget.comicId);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
routeObserver.subscribe(this, ModalRoute.of(context)!);
}
@override
void didPopNext() {
setState(() {
_viewFuture = _loadViewLog();
});
}
2022-07-04 02:02:09 +00:00
@override
void initState() {
if (widget.holdPkz) {
_linkSubscription = linkSubscript(context);
}
super.initState();
}
2021-09-29 23:57:09 +00:00
@override
void dispose() {
2022-07-04 02:02:09 +00:00
_linkSubscription?.cancel();
2021-09-29 23:57:09 +00:00
routeObserver.unsubscribe(this);
super.dispose();
}
@override
2022-07-04 02:02:09 +00:00
Widget build(BuildContext context) {
2022-03-25 14:57:30 +00:00
return rightClickPop(
child: buildScreen(context),
context: context,
canPop: true,
);
2022-03-19 04:12:27 +00:00
}
Widget buildScreen(BuildContext context) {
2021-09-29 23:57:09 +00:00
return FutureBuilder(
2022-06-03 03:19:29 +00:00
key: _comicFutureKey,
2021-09-29 23:57:09 +00:00
future: _comicFuture,
builder: (BuildContext context, AsyncSnapshot<ComicInfo> snapshot) {
if (snapshot.hasError) {
return Scaffold(
appBar: AppBar(),
body: ContentError(
error: snapshot.error,
stackTrace: snapshot.stackTrace,
onRefresh: () async {
setState(() {
_comicFuture = _loadComic();
2022-06-03 03:19:29 +00:00
_comicFutureKey = UniqueKey();
2021-09-29 23:57:09 +00:00
});
},
),
);
}
if (snapshot.connectionState != ConnectionState.done) {
return Scaffold(
appBar: AppBar(),
2022-03-19 04:12:27 +00:00
body: const ContentLoading(label: '加载中'),
2021-09-29 23:57:09 +00:00
);
}
var _comicInfo = snapshot.data!;
var theme = Theme.of(context);
var _tabs = <Widget>[
Tab(text: '章节 (${_comicInfo.epsCount})'),
Tab(text: '评论 (${_comicInfo.commentsCount})'),
2022-04-18 02:55:08 +00:00
const Tab(text: '推荐'),
2021-09-29 23:57:09 +00:00
];
var _views = <Widget>[
_buildEpWrap(_epListFuture, _comicInfo),
2021-11-09 21:57:44 +00:00
CommentList(CommentMainType.COMIC, _comicInfo.id),
2022-04-18 02:55:08 +00:00
Recommendation(comicId: _comicInfo.id),
2021-09-29 23:57:09 +00:00
];
return DefaultTabController(
length: _tabs.length,
child: Scaffold(
appBar: AppBar(
title: Text(_comicInfo.title),
actions: [
_buildDownloadAction(_epListFuture, _comicInfo),
],
),
2023-05-08 09:57:28 +00:00
body: PikaListView(
2021-09-29 23:57:09 +00:00
children: [
ComicInfoCard(_comicInfo, linkItem: true),
ComicTagsCard(_comicInfo.tags),
ComicDescriptionCard(description: _comicInfo.description),
Container(
2022-03-19 04:12:27 +00:00
padding: const EdgeInsets.all(10),
2021-09-29 23:57:09 +00:00
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: theme.dividerColor,
),
),
),
child: Wrap(
alignment: WrapAlignment.spaceBetween,
children: [
Text.rich(TextSpan(
children: [
WidgetSpan(
child: GestureDetector(
onTap: () {
if (_comicInfo.creator.id != "") {
navPushOrReplace(
context,
(context) => ComicsScreen(
creatorId: _comicInfo.creator.id,
creatorName: _comicInfo.creator.name,
),
);
}
},
onLongPress: () {
confirmCopy(
context,
2022-03-17 03:31:25 +00:00
_comicInfo.creator.name,
2021-09-29 23:57:09 +00:00
);
},
child: Text(
2022-03-17 03:31:25 +00:00
_comicInfo.creator.name,
style: const TextStyle(
2021-09-29 23:57:09 +00:00
fontSize: 14,
color: Colors.grey,
),
),
),
),
2022-03-17 03:31:25 +00:00
const TextSpan(
2021-09-29 23:57:09 +00:00
text: " ",
style: TextStyle(
fontSize: 14,
color: Colors.grey,
),
),
TextSpan(
text:
"( ${formatTimeToDate(_comicInfo.updatedAt)} )",
2022-03-19 04:12:27 +00:00
style: const TextStyle(
2021-09-29 23:57:09 +00:00
fontSize: 13,
color: Colors.grey,
),
),
],
)),
GestureDetector(
onTap: () {
if (_comicInfo.chineseTeam != "") {
navPushOrReplace(
context,
(context) => ComicsScreen(
chineseTeam: _comicInfo.chineseTeam,
),
);
}
},
onLongPress: () {
confirmCopy(context, _comicInfo.chineseTeam);
},
child: Text(
2022-03-17 03:31:25 +00:00
_comicInfo.chineseTeam,
style: const TextStyle(
2021-09-29 23:57:09 +00:00
fontSize: 13,
color: Colors.grey,
),
),
),
],
),
),
Container(height: 5),
Container(
height: 40,
color: theme.colorScheme.secondary.withOpacity(.025),
child: TabBar(
tabs: _tabs,
indicatorColor: theme.colorScheme.secondary,
labelColor: theme.colorScheme.secondary,
onTap: (val) async {
setState(() {
_tabIndex = val;
});
},
),
),
Container(height: 15),
_views[_tabIndex],
Container(height: 5),
],
),
),
);
},
);
}
Widget _buildDownloadAction(
Future<List<Ep>> _epListFuture,
ComicInfo _comicInfo,
) {
return FutureBuilder(
future: _epListFuture,
builder: (BuildContext context, AsyncSnapshot<List<Ep>> snapshot) {
if (snapshot.hasError) {
return IconButton(
onPressed: () {
setState(() {
2022-03-03 02:36:44 +00:00
this._epListFuture = _loadEps();
2021-09-29 23:57:09 +00:00
});
},
2022-03-19 04:12:27 +00:00
icon: const Icon(Icons.sync_problem),
2021-09-29 23:57:09 +00:00
);
}
if (snapshot.connectionState != ConnectionState.done) {
2022-03-19 04:12:27 +00:00
return IconButton(onPressed: () {}, icon: const Icon(Icons.sync));
2021-09-29 23:57:09 +00:00
}
var _epList = snapshot.data!;
return IconButton(
onPressed: () async {
Navigator.push(
context,
2023-01-31 10:50:51 +00:00
mixRoute(
2021-09-29 23:57:09 +00:00
builder: (context) => DownloadConfirmScreen(
comicInfo: _comicInfo,
epList: _epList.reversed.toList(),
),
),
);
},
2022-03-19 04:12:27 +00:00
icon: const Icon(Icons.download_rounded),
2021-09-29 23:57:09 +00:00
);
},
);
}
Widget _buildEpWrap(Future<List<Ep>> _epListFuture, ComicInfo _comicInfo) {
return ItemBuilder(
future: _epListFuture,
successBuilder: (BuildContext context, AsyncSnapshot<List<Ep>> snapshot) {
var _epList = snapshot.data!;
return Column(
children: [
ContinueReadButton(
viewFuture: _viewFuture,
onChoose: (int? epOrder, int? pictureRank) {
if (epOrder != null && pictureRank != null) {
for (var i in _epList) {
if (i.order == epOrder) {
_push(_comicInfo, _epList, epOrder, pictureRank);
return;
}
}
} else {
_push(
_comicInfo, _epList, _epList.reversed.first.order, null);
return;
}
},
),
Wrap(
spacing: 10,
runSpacing: 10,
alignment: WrapAlignment.spaceAround,
children: [
..._epList.map((e) {
2022-03-17 03:31:25 +00:00
return MaterialButton(
onPressed: () {
_push(_comicInfo, _epList, e.order, null);
},
color: Colors.white,
2022-03-19 04:12:27 +00:00
child: Text(
e.title,
style: const TextStyle(color: Colors.black),
),
2021-09-29 23:57:09 +00:00
);
}),
],
),
],
);
},
onRefresh: () async {
setState(() {
_epListFuture = _loadEps();
});
},
);
}
void _push(ComicInfo comicInfo, List<Ep> epList, int order, int? rank) {
Navigator.push(
context,
2023-01-31 10:50:51 +00:00
mixRoute(
2021-09-29 23:57:09 +00:00
builder: (context) => ComicReaderScreen(
comicInfo: comicInfo,
epList: epList,
currentEpOrder: order,
2021-11-30 10:49:51 +00:00
initPicturePosition: rank,
2021-09-29 23:57:09 +00:00
),
),
);
}
}