390 lines
11 KiB
Dart
390 lines
11 KiB
Dart
import 'dart:math';
|
|
|
|
import 'package:event/event.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:pikapika/basic/Common.dart';
|
|
import 'package:pikapika/basic/Entities.dart';
|
|
import 'package:pikapika/basic/Method.dart';
|
|
import 'package:pikapika/basic/config/ShadowCategories.dart';
|
|
import 'package:pikapika/basic/config/ListLayout.dart';
|
|
import 'package:pikapika/basic/config/shadowCategoriesMode.dart';
|
|
|
|
import 'ComicInfoCard.dart';
|
|
import 'Images.dart';
|
|
import 'LinkToComicInfo.dart';
|
|
|
|
// 漫画列表页
|
|
class ComicList extends StatefulWidget {
|
|
final Widget? appendWidget;
|
|
final List<ComicSimple> comicList;
|
|
final ScrollController? controller;
|
|
|
|
const ComicList(
|
|
this.comicList, {
|
|
this.appendWidget,
|
|
this.controller,
|
|
Key? key,
|
|
}) : super(key: key);
|
|
|
|
@override
|
|
State<StatefulWidget> createState() => _ComicListState();
|
|
}
|
|
|
|
class _ComicListState extends State<ComicList> {
|
|
final List<String> viewedList = [];
|
|
|
|
Future _loadViewed() async {
|
|
if (widget.comicList.isNotEmpty) {
|
|
viewedList.addAll(await method
|
|
.loadViewedList(widget.comicList.map((e) => e.id).toList()));
|
|
setState(() {});
|
|
}
|
|
}
|
|
|
|
@override
|
|
void initState() {
|
|
_loadViewed();
|
|
listLayoutEvent.subscribe(_onLayoutChange);
|
|
super.initState();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
listLayoutEvent.unsubscribe(_onLayoutChange);
|
|
super.dispose();
|
|
}
|
|
|
|
void _onLayoutChange(EventArgs? args) {
|
|
setState(() {});
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
switch (currentLayout) {
|
|
case ListLayout.INFO_CARD:
|
|
return _buildInfoCardList();
|
|
case ListLayout.ONLY_IMAGE:
|
|
return _buildGridImageWarp();
|
|
case ListLayout.COVER_AND_TITLE:
|
|
return _buildGridImageTitleWarp();
|
|
default:
|
|
return Container();
|
|
}
|
|
}
|
|
|
|
Widget _buildInfoCardList() {
|
|
return ListView(
|
|
controller: widget.controller,
|
|
physics: const AlwaysScrollableScrollPhysics(),
|
|
children: [
|
|
...widget.comicList.map((e) {
|
|
late bool shadow;
|
|
X:
|
|
switch (currentShadowCategoriesMode()) {
|
|
case ShadowCategoriesMode.BLACK_LIST:
|
|
shadow = e.categories
|
|
.map((c) => shadowCategories.contains(c))
|
|
.reduce((value, element) => value || element);
|
|
break;
|
|
case ShadowCategoriesMode.WHITE_LIST:
|
|
for (var c in e.categories) {
|
|
if (shadowCategories.contains(c)) {
|
|
shadow = false;
|
|
break X;
|
|
}
|
|
}
|
|
shadow = true;
|
|
break;
|
|
}
|
|
if (shadow) {
|
|
return InkWell(
|
|
onTap: () {},
|
|
child: Container(
|
|
padding: const EdgeInsets.all(10),
|
|
decoration: BoxDecoration(
|
|
border: Border(
|
|
bottom: BorderSide(
|
|
color: Theme.of(context).dividerColor,
|
|
),
|
|
),
|
|
),
|
|
child: Center(
|
|
child: Text(
|
|
'被封印的本子',
|
|
style: TextStyle(
|
|
fontSize: 12,
|
|
color: (Theme.of(context).textTheme.bodyText1?.color ??
|
|
Colors.black)
|
|
.withOpacity(.3),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
return LinkToComicInfo(
|
|
comicId: e.id,
|
|
child: ComicInfoCard(
|
|
e,
|
|
viewed: viewedList.contains(e.id),
|
|
),
|
|
);
|
|
}).toList(),
|
|
...widget.appendWidget != null
|
|
? [
|
|
SizedBox(
|
|
height: 80,
|
|
child: widget.appendWidget,
|
|
),
|
|
]
|
|
: [],
|
|
],
|
|
);
|
|
}
|
|
|
|
Widget _buildGridImageWarp() {
|
|
var gap = 3.0;
|
|
var size = MediaQuery.of(context).size;
|
|
var min = size.width < size.height ? size.width : size.height;
|
|
var widthAndGap = min / 4;
|
|
int rowCap = size.width ~/ widthAndGap;
|
|
var width = widthAndGap - gap * 2;
|
|
var height = width * coverHeight / coverWidth;
|
|
List<Widget> wraps = [];
|
|
List<Widget> tmp = [];
|
|
for (var e in widget.comicList) {
|
|
var shadow = e.categories.map(
|
|
(c) {
|
|
switch (currentShadowCategoriesMode()) {
|
|
case ShadowCategoriesMode.BLACK_LIST:
|
|
if (shadowCategories.contains(c)) return true;
|
|
break;
|
|
case ShadowCategoriesMode.WHITE_LIST:
|
|
if (!shadowCategories.contains(c)) return true;
|
|
break;
|
|
}
|
|
return false;
|
|
},
|
|
).reduce((value, element) => value || element);
|
|
if (shadow) {
|
|
tmp.add(
|
|
Container(
|
|
padding: EdgeInsets.all(gap),
|
|
child: Container(
|
|
width: width,
|
|
height: height,
|
|
color:
|
|
(Theme.of(context).textTheme.bodyText1?.color ?? Colors.black)
|
|
.withOpacity(.05),
|
|
child: Center(
|
|
child: Text(
|
|
'被封印的本子',
|
|
textAlign: TextAlign.center,
|
|
style: TextStyle(
|
|
fontSize: 12,
|
|
color: (Theme.of(context).textTheme.bodyText1?.color ??
|
|
Colors.black)
|
|
.withOpacity(.5),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
} else {
|
|
tmp.add(LinkToComicInfo(
|
|
comicId: e.id,
|
|
child: Container(
|
|
padding: EdgeInsets.all(gap),
|
|
child: RemoteImage(
|
|
fileServer: e.thumb.fileServer,
|
|
path: e.thumb.path,
|
|
width: width,
|
|
height: height,
|
|
),
|
|
),
|
|
));
|
|
}
|
|
if (tmp.length == rowCap) {
|
|
wraps.add(Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
children: tmp,
|
|
));
|
|
tmp = [];
|
|
}
|
|
}
|
|
// 追加特殊按钮
|
|
if (widget.appendWidget != null) {
|
|
tmp.add(Container(
|
|
color:
|
|
(Theme.of(context).textTheme.bodyText1?.color ?? Colors.transparent)
|
|
.withOpacity(.1),
|
|
margin: EdgeInsets.only(
|
|
left: (rowCap - tmp.length) * gap,
|
|
right: (rowCap - tmp.length) * gap,
|
|
top: gap,
|
|
bottom: gap,
|
|
),
|
|
width: (rowCap - tmp.length) * width,
|
|
height: height,
|
|
child: widget.appendWidget,
|
|
));
|
|
}
|
|
// 最后一页没有下一页所有有可能为空
|
|
if (tmp.isNotEmpty) {
|
|
wraps.add(Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
children: tmp,
|
|
));
|
|
tmp = [];
|
|
}
|
|
// 返回
|
|
return ListView(
|
|
controller: widget.controller,
|
|
physics: const AlwaysScrollableScrollPhysics(),
|
|
padding: EdgeInsets.only(top: gap, bottom: gap),
|
|
children: wraps,
|
|
);
|
|
}
|
|
|
|
Widget _buildGridImageTitleWarp() {
|
|
var gap = 3.0;
|
|
var size = MediaQuery.of(context).size;
|
|
var min = size.width < size.height ? size.width : size.height;
|
|
var widthAndGap = min / 3;
|
|
int rowCap = size.width ~/ widthAndGap;
|
|
var width = widthAndGap - gap * 2;
|
|
var height = width * coverHeight / coverWidth;
|
|
double titleFontSize = max(width / 11, 10);
|
|
double shadowFontSize = max(width / 9, 12);
|
|
List<Widget> wraps = [];
|
|
List<Widget> tmp = [];
|
|
for (var e in widget.comicList) {
|
|
var shadow = e.categories.map(
|
|
(c) {
|
|
switch (currentShadowCategoriesMode()) {
|
|
case ShadowCategoriesMode.BLACK_LIST:
|
|
if (shadowCategories.contains(c)) return true;
|
|
break;
|
|
case ShadowCategoriesMode.WHITE_LIST:
|
|
if (!shadowCategories.contains(c)) return true;
|
|
break;
|
|
}
|
|
return false;
|
|
},
|
|
).reduce((value, element) => value || element);
|
|
if (shadow) {
|
|
tmp.add(
|
|
Container(
|
|
padding: EdgeInsets.all(gap),
|
|
child: Container(
|
|
width: width,
|
|
height: height,
|
|
color:
|
|
(Theme.of(context).textTheme.bodyText1?.color ?? Colors.black)
|
|
.withOpacity(.05),
|
|
child: Center(
|
|
child: Text(
|
|
'被封印的本子',
|
|
textAlign: TextAlign.center,
|
|
style: TextStyle(
|
|
fontSize: shadowFontSize,
|
|
color: (Theme.of(context).textTheme.bodyText1?.color ??
|
|
Colors.black)
|
|
.withOpacity(.5),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
} else {
|
|
tmp.add(LinkToComicInfo(
|
|
comicId: e.id,
|
|
child: Container(
|
|
margin: EdgeInsets.all(gap),
|
|
width: width,
|
|
height: height,
|
|
child: Stack(
|
|
children: [
|
|
RemoteImage(
|
|
fileServer: e.thumb.fileServer,
|
|
path: e.thumb.path,
|
|
width: width,
|
|
height: height,
|
|
),
|
|
Align(
|
|
alignment: Alignment.bottomCenter,
|
|
child: Container(
|
|
color: Colors.black.withOpacity(.3),
|
|
child: Row(
|
|
children: [
|
|
Expanded(
|
|
child: Text(
|
|
e.title + '\n',
|
|
style: TextStyle(
|
|
color: Colors.white,
|
|
fontSize: titleFontSize,
|
|
height: 1.2,
|
|
),
|
|
strutStyle: const StrutStyle(height: 1.2),
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
));
|
|
}
|
|
if (tmp.length == rowCap) {
|
|
wraps.add(Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
children: tmp,
|
|
));
|
|
tmp = [];
|
|
}
|
|
}
|
|
// 追加特殊按钮
|
|
if (widget.appendWidget != null) {
|
|
tmp.add(Container(
|
|
color:
|
|
(Theme.of(context).textTheme.bodyText1?.color ?? Colors.transparent)
|
|
.withOpacity(.1),
|
|
margin: EdgeInsets.only(
|
|
left: (rowCap - tmp.length) * gap,
|
|
right: (rowCap - tmp.length) * gap,
|
|
top: gap,
|
|
bottom: gap,
|
|
),
|
|
width: (rowCap - tmp.length) * width,
|
|
height: height,
|
|
child: widget.appendWidget,
|
|
));
|
|
}
|
|
// 最后一页没有下一页所有有可能为空
|
|
if (tmp.isNotEmpty) {
|
|
wraps.add(Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
children: tmp,
|
|
));
|
|
tmp = [];
|
|
}
|
|
// 返回
|
|
return ListView(
|
|
controller: widget.controller,
|
|
physics: const AlwaysScrollableScrollPhysics(),
|
|
padding: EdgeInsets.only(top: gap, bottom: gap),
|
|
children: wraps,
|
|
);
|
|
}
|
|
}
|