1
0
mirror of https://github.com/nrop19/weiman_app.git synced 2025-08-02 23:05:48 +08:00
This commit is contained in:
nrop19 2020-01-08 04:57:35 +08:00
parent b86adbb991
commit 4c88153171
12 changed files with 320 additions and 382 deletions

View File

@ -11,7 +11,6 @@ class ActivityBook extends StatefulWidget {
}
class BookState extends State<ActivityBook> {
static BoxDecoration _border;
final GlobalKey<PullToRefreshNotificationState> _refresh = GlobalKey();
ScrollController _scrollController;
@ -26,7 +25,8 @@ class BookState extends State<ActivityBook> {
super.initState();
isFavorite = widget.book.isFavorite();
SchedulerBinding.instance.addPostFrameCallback((_) {
_refresh.currentState.show();
_refresh.currentState
.show(notificationDragOffset: SliverPullToRefreshHeader.height);
});
_scrollController = ScrollController();
}
@ -56,12 +56,13 @@ class BookState extends State<ActivityBook> {
if (isFavorite) Data.addFavorite(book);
_scrollToRead();
isLoading = false;
isSuccess = true;
} catch (e) {
isLoading = false;
isSuccess = false;
return false;
}
isLoading = false;
print('刷新 $book');
setState(() {});
return true;
@ -121,7 +122,7 @@ class BookState extends State<ActivityBook> {
final isRead = chapter.cid == book.history?.cid;
if (index < chapters.length - 1) {
return DecoratedBox(
decoration: _border,
decoration: _Main._border,
child: WidgetChapter(
chapter: chapter,
onTap: _openChapter,
@ -138,10 +139,6 @@ class BookState extends State<ActivityBook> {
@override
Widget build(BuildContext context) {
if (_border == null)
_border = BoxDecoration(
border: Border(
bottom: Divider.createBorderSide(context, color: Colors.grey)));
Color color = isFavorite ? Colors.red : Colors.white;
IconData icon = isFavorite ? Icons.favorite : Icons.favorite_border;
final book = this.book ?? widget.book;
@ -211,8 +208,8 @@ class BookState extends State<ActivityBook> {
),
PullToRefreshContainer((info) => SliverPullToRefreshHeader(
info: info,
onTap: () => _refresh.currentState
.show(notificationDragOffset: kToolbarHeight * 2),
onTap: () => _refresh.currentState.show(
notificationDragOffset: SliverPullToRefreshHeader.height),
)),
SliverList(
delegate: SliverChildBuilderDelegate(

View File

@ -1,24 +1,5 @@
part of '../main.dart';
enum LoadState {
Loading,
Finish,
Timeout,
}
class LoadMoreListSource extends LoadingMoreBase<int> {
@override
Future<bool> loadData([bool isloadMoreAction = false]) {
return Future.delayed(Duration(seconds: 1), () {
for (var i = 0; i < 10; i++) {
this.add(0);
}
return true;
});
}
}
class ActivityChapter extends StatefulWidget {
final Book book;
final Chapter chapter;
@ -77,14 +58,6 @@ class ChapterState extends State<ActivityChapter> {
chapter: widget.book.chapters[index],
);
}),
// floatingActionButton: FloatingActionButton(
// child: Text('下一章'),
// onPressed: () {
// if (hasNextChapter)
// return openChapter(widget.book.chapters[chapterIndex + 1]);
// Fluttertoast.showToast(msg: '已经是最后一章了');
// },
// ),
);
}
}
@ -110,11 +83,9 @@ class _ChapterDrawer extends State<ChapterDrawer> {
@override
void initState() {
super.initState();
_controller = ScrollController();
updateRead();
SchedulerBinding.instance.addPostFrameCallback((_) {
_controller.jumpTo(WidgetChapter.height * read);
});
_controller =
ScrollController(initialScrollOffset: WidgetChapter.height * read);
}
@override
@ -187,68 +158,68 @@ class _ChapterContentView extends State<ChapterContentView> {
BoxDecoration _decoration =
BoxDecoration(color: Colors.black.withOpacity(0.4));
int chapterIndex = -1;
bool hasNextChapter = false;
bool loading = true;
@override
initState() {
super.initState();
chapterIndex = widget.book.chapters.indexOf(widget.chapter);
hasNextChapter = widget.book.chapters.last != widget.chapter;
Data.addHistory(widget.book, widget.chapter);
SchedulerBinding.instance.addPostFrameCallback((_) => _refresh?.currentState
?.show(notificationDragOffset: kToolbarHeight * 2));
?.show(notificationDragOffset: SliverPullToRefreshHeader.height));
}
Future<bool> fetchImages() async {
print('fetchImages');
setState(() {});
if (mounted) setState(() {});
loading = true;
images.clear();
try {
images.addAll(await UserAgentClient.instance
.getImages(aid: widget.book.aid, cid: widget.chapter.cid)
.timeout(const Duration(seconds: 5)));
.timeout(Duration(seconds: 5)));
if (images.length < 5) {
// print('图片 前:' + images.toString());
var list = await checkImage(images.last);
final list =
await checkImage(images.last).timeout(Duration(seconds: 15));
images.addAll(list);
}
} catch (e) {
print('错误');
print('错误 $e');
showToastWidget(
GestureDetector(
child: Container(
child: Text('读取章节内容出现错误\n点击复制错误内容'),
color: Colors.black.withOpacity(0.5),
padding: EdgeInsets.all(10),
),
onTap: () async {
await Clipboard.setData(ClipboardData(text: e.toString()));
final content = await Clipboard.getData(Clipboard.kTextPlain);
print('粘贴板 ${content.text}');
},
),
duration: Duration(seconds: 5),
handleTouch: true,
);
return false;
// throw(e);
}
loading = false;
// print('所有图片:' + images.toString());
setState(() {});
if (mounted) setState(() {});
return true;
}
@override
Widget build(BuildContext context) {
final List<Widget> list = [];
for (var i = 0; i < images.length; i++) {
list.add(SliverStickyHeader(
overlapsContent: true,
header: SafeArea(
top: true,
bottom: false,
child: Row(
children: [
Container(
final list = <Widget>[];
if (!loading && images.length < 20) {
list.add(SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.all(5),
decoration: _decoration,
child: Text(
'${i + 1} / ${images.length}',
style: _style,
),
),
],
),
),
sliver:
SliverToBoxAdapter(child: Image(image: NetworkImageSSL(images[i]))),
));
child: Text('只读取到少于20张图片友情提示\n'
'由于能力有限,可能没有办法识别出本章的所有图片,\n'
'敬请谅解。'))));
}
return PullToRefreshNotification(
key: _refresh,
@ -266,37 +237,100 @@ class _ChapterContentView extends State<ChapterContentView> {
PullToRefreshContainer(
(info) => SliverPullToRefreshHeader(
info: info,
onTap: () => _refresh.currentState
.show(notificationDragOffset: kToolbarHeight * 2),
onTap: () => _refresh.currentState.show(
notificationDragOffset: SliverPullToRefreshHeader.height),
),
),
...list,
SliverList(
delegate: SliverChildBuilderDelegate(
(ctx, i) {
print('item $i');
return StickyHeader(
overlapHeaders: true,
header: SafeArea(
top: true,
bottom: false,
child: Row(
children: [
Container(
padding: EdgeInsets.all(5),
decoration: _decoration,
child: Text(
'${i + 1} / ${images.length}',
style: _style,
),
),
],
),
),
content: ExtendedImage(
image: NetworkImageSSL(images[i]),
enableLoadState: true,
enableMemoryCache: true,
fit: BoxFit.fitWidth,
loadStateChanged: (state) {
switch (state.extendedImageLoadState) {
case LoadState.loading:
return SizedBox(
height: 300,
child: Center(
child: CircularProgressIndicator(),
),
);
break;
case LoadState.failed:
return SizedBox(
width: double.infinity,
height: 300,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('图片读取失败'),
RaisedButton(
child: Text('重试'),
onPressed: state.reLoadImage,
),
],
),
);
break;
default:
return ExtendedRawImage(
image: state.extendedImageInfo?.image,
);
}
},
),
// content: Image(
// image: NetworkImageSSL(images[i]),
// loadingBuilder: (_, child, loadingProgress) {
// if (loadingProgress == null) return child;
// return SizedBox(
// height: 400,
// child: Center(
// child: CircularProgressIndicator(
// value: loadingProgress.expectedTotalBytes != null
// ? loadingProgress.cumulativeBytesLoaded /
// loadingProgress.expectedTotalBytes
// : null,
// ),
// ),
// );
// }),
);
},
childCount: images.length,
),
),
],
),
);
}
}
Future<dynamic> checkImage(String last) async {
final response = new ReceivePort();
await Isolate.spawn(_checkImage, response.sendPort);
final sendPort = await response.first as SendPort;
//ReceivePort
final answer = new ReceivePort();
//
sendPort.send([answer.sendPort, last]);
return answer.first;
}
void _checkImage(SendPort initialReplyTo) {
UserAgentClient.instance = UserAgentClient('chrome');
final port = new ReceivePort();
initialReplyTo.send(port.sendPort);
port.listen((message) async {
//
final send = message[0] as SendPort;
final last = message[1] as String;
//
Future<List<String>> checkImage(String last) async {
final uri = Uri.parse(last);
// print({'scheme': uri.scheme, 'host': uri.host, 'path': uri.path});
final a = uri.scheme + '://' + uri.host;
@ -307,12 +341,11 @@ void _checkImage(SendPort initialReplyTo) {
final fileName = file[0];
//
final fileFormat = file[1];
final list = <String>[];
final List<String> list = [];
int plus = 1;
//print('最后的图片:' + last);
while (true) {
final String file1 =
getFileName(name: fileName, divider: '_', plus: plus),
final String file1 = getFileName(name: fileName, divider: '_', plus: plus),
file2 = getFileName(name: fileName, divider: '_', plus: plus + 1);
var url1 = '$a/$b/$file1.$fileFormat', url2 = '$a/$b/$file2.$fileFormat';
// print('正在测试:\n' + url1 + '\n' + url2);
@ -329,8 +362,7 @@ void _checkImage(SendPort initialReplyTo) {
plus += 2;
}
// print('最后的图片数量: ' + number.toString());
send.send(list);
});
return list;
}
String getFileName(

View File

@ -79,12 +79,7 @@ class _State extends State<ActivityCheckData> {
maxLines: 8,
controller: _outputController,
onTap: () {
Fluttertoast.showToast(
msg: '已经复制',
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIos: 1,
);
showToast('已经复制');
Clipboard.setData(ClipboardData(text: _outputController.text));
},
));

View File

@ -32,9 +32,8 @@ class HomeState extends State<ActivityHome> {
.where((int updatedChapters) => updatedChapters > 0)
.length;
if (updated > 0)
Fluttertoast.showToast(
msg: '$updated 本藏书有更新',
gravity: ToastGravity.CENTER,
showToast(
'$updated 本藏书有更新',
backgroundColor: Colors.black.withOpacity(0.5),
);
});
@ -61,7 +60,7 @@ class HomeState extends State<ActivityHome> {
context,
MaterialPageRoute(
settings: RouteSettings(name: '/activity_recommend/'),
builder: (_) => ActivityRecommend(),
builder: (_) => ActivityRank(),
));
}

View File

@ -1,83 +0,0 @@
part of '../main.dart';
class ActivityRecommend extends StatefulWidget {
@override
_ActivityRecommend createState() => _ActivityRecommend();
}
class _ActivityRecommend extends State<ActivityRecommend> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('月排行榜'),
),
body: BookList(),
);
}
}
class BookList extends StatefulWidget {
const BookList({Key key}) : super(key: key);
@override
_BookList createState() => _BookList();
}
class _BookList extends State<BookList> {
final GlobalKey<RefreshIndicatorState> _refresh = GlobalKey();
final List<Book> books = [];
bool loadFail = false;
@override
void initState() {
super.initState();
SchedulerBinding.instance.addPostFrameCallback((_) {
_refresh.currentState.show();
});
}
Future<void> loadBooks() async {
loadFail = false;
try {
final books = await UserAgentClient.instance
.getMonthList()
.timeout(Duration(seconds: 5));
this.books
..clear()
..addAll(books);
} catch (e) {
loadFail = true;
}
setState(() {});
}
@override
Widget build(BuildContext context) {
return RefreshIndicator(
key: _refresh,
onRefresh: loadBooks,
child: loadFail
? CustomScrollView(
slivers: [
SliverFillRemaining(
child: Center(child: Text('读取失败,下拉刷新')),
)
],
)
: ListView(
children: ListTile.divideTiles(
context: context,
tiles: books.map((book) => WidgetBook(
book,
subtitle: book.author,
))).toList(),
),
);
}
}

View File

@ -14,64 +14,66 @@ class Search extends StatefulWidget {
}
}
enum _SearchState {
None,
Searching,
Done,
Error,
}
class SearchState extends State<Search> {
Future<List<Book>> search;
TextEditingController _controller = TextEditingController();
CancelableOperation _searcher;
_SearchState _state = _SearchState.None;
GlobalKey<PullToRefreshNotificationState> _refresh = GlobalKey();
final List<Book> _books = [];
bool loading;
void startSearch() {
void submit() {
_refresh.currentState
.show(notificationDragOffset: SliverPullToRefreshHeader.height);
}
Future<bool> startSearch() async {
print('搜索漫画: ' + _controller.text);
if (_searcher != null) _searcher.cancel();
setState(() {
loading = true;
});
_books.clear();
setState(() {
_state = _SearchState.Searching;
});
_searcher = CancelableOperation.fromFuture(
UserAgentClient.instance.searchBook(_controller.text))
.then((books) {
setState(() {
print('搜索完成: ' + books.length.toString());
try {
final List<Book> books = await UserAgentClient.instance
.searchBook(_controller.text)
.timeout(Duration(seconds: 5));
_books.addAll(books);
_state = _SearchState.Done;
});
});
loading = false;
} catch (e) {
loading = false;
return false;
}
return true;
}
@override
Widget build(BuildContext context) {
search = null;
return Scaffold(
appBar: AppBar(
title: Text('搜索漫画'),
),
body: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: RawKeyboardListener(
body: PullToRefreshNotification(
key: _refresh,
onRefresh: startSearch,
child: CustomScrollView(slivers: [
SliverAppBar(
pinned: true,
title: RawKeyboardListener(
focusNode: FocusNode(),
onKey: (RawKeyEvent event) {
if (event.runtimeType == RawKeyUpEvent &&
event.logicalKey.debugName.toLowerCase() == 'enter') {
print(
'is enter: ${LogicalKeyboardKey.enter == event.logicalKey}');
if (_controller.text.isEmpty) return;
startSearch();
if (event.runtimeType == RawKeyUpEvent &&
LogicalKeyboardKey.enter == event.logicalKey) {
print('回车键搜索');
submit();
}
},
child: TextField(
decoration: InputDecoration(
hintText: '搜索书名',
prefixIcon: IconButton(
onPressed: startSearch,
onPressed: () {
_refresh.currentState.show(
notificationDragOffset:
SliverPullToRefreshHeader.height);
},
icon: Icon(Icons.search),
),
),
@ -81,54 +83,40 @@ class SearchState extends State<Search> {
textInputAction: TextInputAction.search,
onSubmitted: (String name) {
print('onSubmitted');
startSearch();
submit();
},
keyboardType: TextInputType.text,
onEditingComplete: () {
print('onEditingComplete');
startSearch();
submit();
},
),
),
),
],
),
Expanded(
flex: 1,
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
switch (_state) {
case _SearchState.Searching:
return Center(child: CircularProgressIndicator());
case _SearchState.None:
return Center(
child: Icon(
Icons.search,
color: Colors.grey,
));
default:
if (_books.length == 0)
return Center(
child: Text(
'一本也找不到',
style: TextStyle(color: Colors.blueGrey),
));
List<Widget> list = _books
.map((book) => WidgetBook(
book,
subtitle: book.author,
))
.toList();
return ListView(
children:
ListTile.divideTiles(context: context, tiles: list)
.toList(),
);
PullToRefreshContainer((info) => SliverPullToRefreshHeader(
info: info,
onTap: submit,
)),
SliverLayoutBuilder(
builder: (_, __) {
if (loading == null)
return SliverFillRemaining(
child: Center(child: Text('输入关键词搜索')));
if (loading) return SliverToBoxAdapter();
if (_books.length == 0) {
return SliverFillRemaining(child: Center(child: Text('一本也没有')));
}
return SliverList(
delegate: SliverChildBuilderDelegate((_, i) {
return WidgetBook(
_books[i],
subtitle: _books[i].author,
);
}, childCount: _books.length),
);
},
),
),
],
]),
),
);
}

View File

@ -3,14 +3,15 @@ part of '../main.dart';
const domain = '';
class UserAgentClient extends http.BaseClient {
final String userAgent;
http.Client _inner;
http.Client _inner = http.Client();
String lastKey;
int lastKeyTime = 0;
static UserAgentClient instance;
UserAgentClient(this.userAgent) {
// UserAgentClient(this.userAgent);
UserAgentClient(String userAgent, ByteData data) {
}
Future<String> getKey() async {
@ -21,6 +22,7 @@ class UserAgentClient extends http.BaseClient {
}
Future<List<String>> getImages(
{@required String aid, @required String cid}) async {
}
Future<Book> getBook({String aid}) async {
@ -32,7 +34,7 @@ class UserAgentClient extends http.BaseClient {
Future<List<Book>> searchBook(String name) async {
}
static void init(String userAgent) {
static void init() async {
}
Future<http.Response> _get(url, {Map<String, String> headers}) async {

View File

@ -1,10 +1,4 @@
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/foundation.dart';
import 'package:flutter/painting.dart' as image_provider;
part of '../main.dart';
/// The dart:io implementation of [image_provider.NetworkImage].
class NetworkImageSSL
@ -26,6 +20,8 @@ class NetworkImageSSL
@override
final Map<String, String> headers;
static void init(ByteData data) {}
@override
Future<NetworkImageSSL> obtainKey(
image_provider.ImageConfiguration configuration) {
@ -59,18 +55,12 @@ class NetworkImageSSL
// We set `autoUncompress` to false to ensure that we can trust the value of
// the `Content-Length` HTTP header. We automatically uncompress the content
// in our call to [consolidateHttpClientResponseBytes].
static final HttpClient _sharedHttpClient = HttpClient()
static HttpClient _sharedHttpClient = HttpClient()
..autoUncompress = false
..badCertificateCallback = (_, __, ___) => true;
static HttpClient get _httpClient {
HttpClient client = _sharedHttpClient;
assert(() {
if (image_provider.debugNetworkImageHttpClientProvider != null)
client = image_provider.debugNetworkImageHttpClientProvider();
return true;
}());
return client;
return _sharedHttpClient;
}
Future<ui.Codec> _loadAsync(
@ -82,7 +72,8 @@ class NetworkImageSSL
assert(key == this);
final Uri resolved = Uri.base.resolve(key.url);
final HttpClientRequest request = await _httpClient.getUrl(resolved);
final HttpClientRequest request =
await _httpClient.getUrl(resolved).timeout(Duration(seconds: 5));
headers?.forEach((String name, String value) {
request.headers.add(name, value);
});

View File

@ -1,31 +1,38 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:isolate';
import 'dart:math' as math;
import 'dart:math';
import 'package:async/async.dart';
import 'package:draggable_container/draggable_container.dart';
import 'package:dynamic_theme/dynamic_theme.dart';
import 'package:encrypt/encrypt.dart' as encrypt;
import 'package:extended_image/extended_image.dart';
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';
import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:firebase_analytics/observer.dart';
import 'package:flutter/material.dart' hide NestedScrollView;
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'package:flutter_sticky_header/flutter_sticky_header.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:html/parser.dart' as html;
import 'package:http/http.dart' as http;
import 'package:http/io_client.dart';
import 'package:loading_more_list/loading_more_list.dart';
import 'package:oktoast/oktoast.dart';
import 'package:package_info/package_info.dart';
import 'package:pull_to_refresh_notification/pull_to_refresh_notification.dart'
hide CircularProgressIndicator;
import 'package:shared_preferences/shared_preferences.dart';
import 'package:sticky_headers/sticky_headers/widget.dart';
import 'package:url_launcher/url_launcher.dart';
import 'classes/networkImageSSL.dart';
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/foundation.dart';
import 'package:flutter/painting.dart' as image_provider;
part './activities/book.dart';
@ -35,7 +42,7 @@ part './activities/checkData.dart';
part './activities/home.dart';
part './activities/recommend.dart';
part './activities/rank.dart';
part './activities/search.dart';
@ -47,6 +54,8 @@ part './classes/data.dart';
part './classes/http.dart';
part './classes/networkImageSSL.dart';
part './widgets/book.dart';
part './widgets/favorites.dart';
@ -69,6 +78,7 @@ FirebaseAnalyticsObserver observer;
const bool isDevMode = !bool.fromEnvironment('dart.vm.product');
void main() async {
FlutterError.onError = (FlutterErrorDetails details) {};
WidgetsFlutterBinding.ensureInitialized();
try {
@ -82,8 +92,8 @@ void main() async {
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown])
]);
final PackageInfo packageInfo = await PackageInfo.fromPlatform();
UserAgentClient.init(
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36');
UserAgentClient.init();
runApp(Main(packageInfo: packageInfo));
}
@ -97,32 +107,27 @@ class Main extends StatefulWidget {
}
class _Main extends State<Main> with WidgetsBindingObserver {
static BoxDecoration _border;
@override
Widget build(BuildContext context) {
if (_border == null)
_border = BoxDecoration(
border: Border(
bottom: Divider.createBorderSide(context, color: Colors.grey)));
return DynamicTheme(
defaultBrightness: Brightness.dark,
data: (brightness) => new ThemeData(
brightness: brightness,
),
themedWidgetBuilder: (context, theme) {
return new MaterialApp(
return OKToast(
child: MaterialApp(
title: 'Flutter Demo',
theme: theme,
home: ActivityHome(widget.packageInfo),
),
);
});
// return MaterialApp(
// title: '微漫',
// theme: ThemeData(
// brightness: Brightness.light,
// ),
// darkTheme: ThemeData(
// brightness: Brightness.dark,
// ),
// themeMode: ThemeMode.system,
// debugShowCheckedModeBanner: false,
// navigatorObservers: [observer],
// home: ActivityHome(widget.packageInfo),
// );
}
}

View File

@ -44,9 +44,8 @@ class _FavoriteList extends State<FavoriteList> {
if (all.isNotEmpty) {
if (showTip == false) {
showTip = true;
Fluttertoast.showToast(
msg: '下拉列表可以检查漫画更新',
gravity: ToastGravity.CENTER,
showToast(
'下拉列表可以检查漫画更新',
backgroundColor: Colors.black.withOpacity(0.5),
);
}
@ -174,7 +173,9 @@ class FBookItem extends StatelessWidget {
Widget build(BuildContext context) {
return ListTile(
onTap: () => onTap(book),
leading: Hero(tag: 'fb ${book.aid}', child: Image(image:NetworkImageSSL(book.avatar))),
leading: Hero(
tag: 'fb ${book.aid}',
child: Image(image: NetworkImageSSL(book.avatar))),
title: Text(book.name, style: Theme.of(context).textTheme.body1),
subtitle: RichText(text: subtitle),
);

View File

@ -1,6 +1,7 @@
part of '../main.dart';
class SliverPullToRefreshHeader extends StatelessWidget {
static final double height = kToolbarHeight * 2;
final PullToRefreshScrollNotificationInfo info;
final void Function() onTap;
final double fontSize;
@ -24,7 +25,7 @@ class SliverPullToRefreshHeader extends StatelessWidget {
WidgetSpan(
baseline: TextBaseline.alphabetic,
child: Padding(
child: Image.asset("images/logo.png", height: 20),
child: Image.asset("assets/logo.png", height: 20),
padding: EdgeInsets.only(right: 5),
),
),
@ -32,7 +33,7 @@ class SliverPullToRefreshHeader extends StatelessWidget {
if (info.mode == RefreshIndicatorMode.error) {
text.children.addAll([
TextSpan(
text: '读取失败\n当失败次数太多请检查网络情况\n有些很旧的章节会看不到,请见谅\n',
text: '读取失败\n当失败次数太多可能是网络出现问题\n',
style: TextStyle(
color: Colors.red,
),

View File

@ -5,8 +5,10 @@ class QuickBook extends DraggableItem {
Widget child;
final BuildContext context;
final Book book;
final double width, height;
QuickBook({@required this.book, @required this.context}) {
QuickBook(this.width, this.height,
{@required this.book, @required this.context}) {
child = GestureDetector(
onTap: () {
Navigator.push(
@ -19,9 +21,16 @@ class QuickBook extends DraggableItem {
},
child: Stack(
children: <Widget>[
Hero(
SizedBox(
width: width,
height: height,
child: Hero(
tag: '$heroTag ${book.aid}',
child: Image(image: NetworkImageSSL(book.avatar)),
child: Image(
image: NetworkImageSSL(book.avatar),
fit: BoxFit.cover,
),
),
),
Positioned(
left: 0,
@ -68,6 +77,7 @@ class QuickState extends State<Quick> {
DraggableItem _addButton;
GlobalKey<DraggableContainerState> _key = GlobalKey();
final List<String> id = [];
double width = 0, height = 0;
void exit() {
_key.currentState.draggableMode = false;
@ -134,8 +144,8 @@ class QuickState extends State<Quick> {
final book = await _showSelectBookDialog();
print('选择了 $book');
if (book == null) return;
_key.currentState.insteadOfIndex(
buttonIndex, QuickBook(book: book, context: context),
_key.currentState.insteadOfIndex(buttonIndex,
QuickBook(width, height, book: book, context: context),
force: true);
}
},
@ -151,9 +161,11 @@ class QuickState extends State<Quick> {
void initState() {
super.initState();
width = widget.width / 4 - 10;
height = (width / 0.7).roundToDouble();
_draggableItems.addAll(Data.quickList().map((book) {
id.add(book.aid);
return QuickBook(book: book, context: context);
return QuickBook(width, height, book: book, context: context);
}));
if (_draggableItems.length < count) _draggableItems.add(_addButton);
for (var i = count - _draggableItems.length; i > 0; i--) {
@ -163,8 +175,6 @@ class QuickState extends State<Quick> {
@override
Widget build(BuildContext context) {
final width = widget.width / 4 - 10;
final height = (width / 0.7).roundToDouble();
return Column(
children: <Widget>[
Container(