🚀 v1.7.4

This commit is contained in:
niuhuan 2023-05-08 17:57:28 +08:00
parent 260aea01cd
commit e57be1a892
44 changed files with 514 additions and 302 deletions

View File

@ -47,6 +47,9 @@ android {
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig signingConfigs.debug
}
debug {
applicationIdSuffix ".debug"
}
}
}

View File

@ -1 +1 @@
v1.7.3
v1.7.4

View File

@ -1,4 +1,3 @@
v1.7.3
- [x] ✨ 可以隐藏发电图标(设置项)
- [x] ✨ 可以给阅读器加灰度滤镜(设置项)(彩色墨水屏下或许有用)
- [x] ✨ 可以选择阅读器背景色(设置项)(白色可防止墨水屏下拖影)
v1.7.4
- [x] ♻️ 优化发电
- [x] ♻️ 优化设置

View File

@ -20,9 +20,10 @@ Widget categoriesColumnCountSetting() {
builder: (BuildContext context, void Function(void Function()) setState) {
return ListTile(
title: const Text(
"首页分类列数",
"首页分类展示列数",
),
subtitle: Text("$categoriesColumnCount"),
subtitle:
Text(categoriesColumnCount == 0 ? "自动" : "$categoriesColumnCount"),
onTap: () async {
int? value = await chooseMapDialog(
context,
@ -33,7 +34,7 @@ Widget categoriesColumnCountSetting() {
"4": 4,
"5": 5,
},
"选择首页分类列数");
"选择首页分类展示列数");
if (value != null) {
await method.saveProperty(_propertyName, "$value");
categoriesColumnCount = value;

View File

@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
import '../Method.dart';
const _propertyName = "eBookScrolling";
late bool _eBookScrolling;
bool get eBookScrolling => _eBookScrolling;
Future initEBookScrolling() async {
_eBookScrolling = (await method.loadProperty(_propertyName, "false")) == "true";
}
Widget eBookScrollingSetting() {
return StatefulBuilder(
builder: (BuildContext context, void Function(void Function()) setState) {
return SwitchListTile(
title: const Text("电子书模式滚动UI"),
value: _eBookScrolling,
onChanged: (value) async {
await method.saveProperty(_propertyName, "$value");
_eBookScrolling = value;
setState(() {});
},
);
},
);
}

View File

@ -0,0 +1,37 @@
import 'package:flutter/material.dart';
import '../Method.dart';
const _propertyName = "eBookScrollingRange";
late int _eBookScrollingRange;
Future initEBookScrollingRange() async {
_eBookScrollingRange =
int.parse((await method.loadProperty(_propertyName, "80")));
}
double get eBookScrollingRange => _eBookScrollingRange / 100;
Widget eBookScrollingRangeSetting() {
return StatefulBuilder(
builder: (BuildContext context, void Function(void Function()) setState) {
return ListTile(
title: Text("电子书模式滚动UI - 滚动幅度 : $_eBookScrollingRange%屏幕高度"),
subtitle: Slider(
min: 30.toDouble(),
max: 80.toDouble(),
value: _eBookScrollingRange.toDouble(),
onChanged: (double value) async {
final va = value.toInt();
await method.loadProperty(_propertyName, "$va");
setState(() {
_eBookScrollingRange = va;
});
},
divisions: (80 - 30),
),
);
},
);
}

View File

@ -0,0 +1,36 @@
import 'package:flutter/material.dart';
import '../Method.dart';
const _propertyName = "eBookScrollingTrigger";
late double _eBookScrollingTrigger;
Future initEBookScrollingTrigger() async {
_eBookScrollingTrigger =
double.parse((await method.loadProperty(_propertyName, "0.3")));
}
double get eBookScrollingTrigger => _eBookScrollingTrigger;
Widget eBookScrollingTriggerSetting() {
return StatefulBuilder(
builder: (BuildContext context, void Function(void Function()) setState) {
return ListTile(
title: Text("电子书模式滚动UI - 触发距离 : $_eBookScrollingTrigger 厘米"),
subtitle: Slider(
min: 0.1.toDouble(),
max: 2.0.toDouble(),
value: _eBookScrollingTrigger.toDouble(),
onChanged: (double value) async {
await method.saveProperty(_propertyName, "$value");
setState((){
_eBookScrollingTrigger = value;
});
},
divisions: (20 - 1),
),
);
},
);
}

View File

@ -19,7 +19,6 @@ Widget hiddenFdIconSetting() {
builder: (BuildContext context, void Function(void Function()) setState) {
return SwitchListTile(
title: const Text("隐藏个人空间的发电图标"),
subtitle: Text(_hiddenFdIcon ? "" : ""),
value: _hiddenFdIcon,
onChanged: (value) async {
await method.saveProperty(_propertyName, "$value");

View File

@ -31,7 +31,6 @@ Widget iconLoadingSetting() {
builder: (BuildContext context, void Function(void Function()) setState) {
return ListTile(
title: const Text("尽量减少UI动画"),
subtitle: Text(_iconLoading ? "" : ""),
onTap: () async {
await _chooseIconLoading(context);
setState(() {});

View File

@ -19,29 +19,20 @@ bool currentUsingRightClickPop() {
return _usingRightClickPop;
}
Future<void> _chooseUsingRightClickPop(BuildContext context) async {
String? result =
await chooseListDialog<String>(context, "鼠标右键返回上一页", ["", ""]);
if (result != null) {
var target = result == "";
await method.saveProperty(_propertyName, "$target");
_usingRightClickPop = target;
}
}
Widget usingRightClickPopSetting() {
if (!(Platform.isWindows || Platform.isMacOS || Platform.isLinux)) {
return Container();
}
return StatefulBuilder(
builder: (BuildContext context, void Function(void Function()) setState) {
return ListTile(
return SwitchListTile(
title: const Text("鼠标右键返回上一页"),
subtitle: Text(_usingRightClickPop ? "" : ""),
onTap: () async {
await _chooseUsingRightClickPop(context);
onChanged: (value) async {
await method.saveProperty(_propertyName, "${value ? "" : ""}");
_usingRightClickPop = value;
setState(() {});
},
value: _usingRightClickPop,
);
},
);

View File

@ -17,8 +17,7 @@ Widget willPopNoticeSetting() {
return StatefulBuilder(
builder: (BuildContext context, void Function(void Function()) setState) {
return SwitchListTile(
title: const Text("退出APP的提示"),
subtitle: Text(_willPopNotice ? "" : ""),
title: const Text("在首页连续按两下返回键才能退出APP"),
value: _willPopNotice,
onChanged: (value) async {
await method.saveProperty(_propertyName, "$value");

View File

@ -5,6 +5,7 @@ import 'package:pikapika/basic/Cross.dart';
import 'package:pikapika/basic/config/Version.dart';
import 'package:pikapika/screens/components/Badge.dart';
import 'components/ListView.dart';
import 'components/RightClickPop.dart';
const _releasesUrl = "https://github.com/niuhuan/pikapika/releases";
@ -54,7 +55,7 @@ class _AboutScreenState extends State<AboutScreen> {
appBar: AppBar(
title: const Text('关于'),
),
body: ListView(
body: PikaListView(
children: [
SizedBox(
width: min / 2,

View File

@ -15,6 +15,7 @@ import 'AppScreen.dart';
import 'DownloadListScreen.dart';
import 'ForgotPasswordScreen.dart';
import 'components/ContentLoading.dart';
import 'components/ListView.dart';
//
class AccountScreen extends StatefulWidget {
@ -102,7 +103,7 @@ class _AccountScreenState extends State<AccountScreen> {
),
],
),
body: ListView(
body: PikaListView(
children: [
ListTile(
title: const Text("账号"),

View File

@ -20,6 +20,7 @@ import 'RandomComicsScreen.dart';
import 'components/Common.dart';
import 'components/ContentLoading.dart';
import 'components/Images.dart';
import 'components/ListView.dart';
//
class CategoriesScreen extends StatefulWidget {
@ -127,7 +128,7 @@ class _CategoriesScreenState extends State<CategoriesScreen> {
if (snapshot.connectionState != ConnectionState.done) {
return const ContentLoading(label: '加载中');
}
return ListView(
return PikaListView(
children: [
Container(height: 20),
Wrap(

View File

@ -21,6 +21,7 @@ import 'components/CommentList.dart';
import 'components/ContentError.dart';
import 'components/ContentLoading.dart';
import 'components/ContinueReadButton.dart';
import 'components/ListView.dart';
import 'components/RightClickPop.dart';
//
@ -146,7 +147,7 @@ class _ComicInfoScreenState extends State<ComicInfoScreen> with RouteAware {
_buildDownloadAction(_epListFuture, _comicInfo),
],
),
body: ListView(
body: PikaListView(
children: [
ComicInfoCard(_comicInfo, linkItem: true),
ComicTagsCard(_comicInfo.tags),

View File

@ -7,6 +7,7 @@ import 'package:pikapika/screens/components/CommentItem.dart';
import 'package:pikapika/screens/components/CommentMainType.dart';
import 'package:pikapika/screens/components/ContentBuilder.dart';
import 'components/ListView.dart';
import 'components/RightClickPop.dart';
class _CommentChildPage extends e.Page {
@ -67,7 +68,7 @@ class _CommentScreenState extends State<CommentScreen> {
successBuilder:
(BuildContext context, AsyncSnapshot<_CommentChildPage> snapshot) {
var page = snapshot.data!;
return ListView(
return PikaListView(
children: [
_buildPrePage(page),
...page.docs.map((e) => _buildComment(e)),

View File

@ -7,6 +7,7 @@ import 'package:pikapika/screens/components/ContentLoading.dart';
import 'package:pikapika/basic/Method.dart';
import 'components/ComicInfoCard.dart';
import 'components/ListView.dart';
import 'components/RightClickPop.dart';
//
@ -128,7 +129,7 @@ class _DownloadConfirmScreenState extends State<DownloadConfirmScreen> {
if (snapshot.connectionState != ConnectionState.done) {
return const ContentLoading(label: '加载中');
}
return ListView(
return PikaListView(
children: [
ComicInfoCard(widget.comicInfo),
_buildButtons(),

View File

@ -7,6 +7,7 @@ import '../basic/config/IconLoading.dart';
import 'DownloadExportingGroupScreen.dart';
import 'components/ContentLoading.dart';
import 'components/DownloadInfoCard.dart';
import 'components/ListView.dart';
class DownloadExportGroupScreen extends StatefulWidget {
const DownloadExportGroupScreen({Key? key}) : super(key: key);
@ -72,7 +73,7 @@ class _DownloadExportGroupScreenState extends State<DownloadExportGroupScreen> {
_f = method.allDownloads("");
});
},
child: ListView(
child: PikaListView(
children: ws,
),
),

View File

@ -12,6 +12,7 @@ import '../basic/config/IsPro.dart';
import 'components/ContentError.dart';
import 'components/ContentLoading.dart';
import 'components/DownloadInfoCard.dart';
import 'components/ListView.dart';
import 'components/RightClickPop.dart';
//
@ -94,7 +95,7 @@ class _DownloadExportToFileScreenState
if (snapshot.connectionState != ConnectionState.done) {
return const ContentLoading(label: '加载中');
}
return ListView(
return PikaListView(
children: [
DownloadInfoCard(task: _task),
Container(

View File

@ -8,6 +8,7 @@ import 'package:pikapika/basic/Method.dart';
import 'components/ContentError.dart';
import 'components/ContentLoading.dart';
import 'components/DownloadInfoCard.dart';
import 'components/ListView.dart';
import 'components/RightClickPop.dart';
//
@ -85,7 +86,7 @@ class _DownloadExportToSocketScreenState
if (snapshot.connectionState != ConnectionState.done) {
return const ContentLoading(label: '加载中');
}
return ListView(
return PikaListView(
children: [
DownloadInfoCard(task: widget.task),
Container(

View File

@ -1,15 +1,12 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:pikapika/basic/Common.dart';
import '../basic/Channels.dart';
import '../basic/Cross.dart';
import '../basic/Method.dart';
import '../basic/config/ExportPath.dart';
import '../basic/config/ExportRename.dart';
import '../basic/config/IsPro.dart';
import 'components/ContentLoading.dart';
import 'components/ListView.dart';
class DownloadExportingGroupScreen extends StatefulWidget {
final List<String> idList;
@ -57,7 +54,7 @@ class _DownloadExportingGroupScreenState
if (exported) {
return const Center(child: Text("导出成功"));
}
return ListView(
return PikaListView(
children: [
Container(height: 20),
displayExportPathInfo(),

View File

@ -14,6 +14,7 @@ import '../basic/config/ImportNotice.dart';
import '../basic/config/IsPro.dart';
import 'PkzArchiveScreen.dart';
import 'components/ContentLoading.dart';
import 'components/ListView.dart';
import 'components/RightClickPop.dart';
//
@ -68,7 +69,7 @@ class _DownloadImportScreenState extends State<DownloadImportScreen> {
appBar: AppBar(
title: const Text('导入'),
),
body: ListView(
body: PikaListView(
children: [
Container(
padding: const EdgeInsets.all(10),

View File

@ -17,6 +17,7 @@ import 'components/ContentError.dart';
import 'components/ContentLoading.dart';
import 'components/ContinueReadButton.dart';
import 'components/DownloadInfoCard.dart';
import 'components/ListView.dart';
import 'components/Recommendation.dart';
//
@ -122,7 +123,7 @@ class _DownloadInfoScreenState extends State<DownloadInfoScreen>
}
List<dynamic> tagsDynamic = json.decode(_task.tags);
List<String> tags = tagsDynamic.map((e) => "$e").toList();
var list = ListView(
var list = PikaListView(
children: [
DownloadInfoCard(task: _task, linkItem: true),
ComicTagsCard(tags),

View File

@ -13,6 +13,7 @@ import 'DownloadImportScreen.dart';
import 'DownloadInfoScreen.dart';
import 'components/ContentLoading.dart';
import 'components/DownloadInfoCard.dart';
import 'components/ListView.dart';
import 'components/RightClickPop.dart';
//
@ -118,7 +119,7 @@ class _DownloadListScreenState extends State<DownloadListScreen> {
_f = method.allDownloads(_search);
});
},
child: ListView(
child: PikaListView(
children: [
...data.map(downloadWidget),
],

View File

@ -4,6 +4,7 @@ import '../basic/Common.dart';
import '../basic/Cross.dart';
import '../basic/Method.dart';
import 'components/ContentLoading.dart';
import 'components/ListView.dart';
class ForgotPasswordScreen extends StatefulWidget {
const ForgotPasswordScreen({Key? key}) : super(key: key);
@ -50,7 +51,7 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
}
Widget _inputEmailScreen() {
return ListView(children: [
return PikaListView(children: [
ListTile(
title: const Text("账号"),
subtitle: Text(_email == "" ? "未设置" : _email),

View File

@ -5,6 +5,7 @@ import 'package:pikapika/basic/Method.dart';
import 'package:pikapika/screens/components/ItemBuilder.dart';
import 'components/GameTitleCard.dart';
import 'components/ListView.dart';
import 'components/RightClickPop.dart';
//
@ -35,7 +36,7 @@ class _GameDownloadScreenState extends State<GameDownloadScreen> {
appBar: AppBar(
title: Text("下载 - ${widget.info.title}"),
),
body: ListView(
body: PikaListView(
children: [
GameTitleCard(widget.info),
ItemBuilder(

View File

@ -7,6 +7,7 @@ import 'package:pikapika/screens/components/ContentBuilder.dart';
import '../basic/config/IconLoading.dart';
import 'GameInfoScreen.dart';
import 'components/Images.dart';
import 'components/ListView.dart';
import 'components/RightClickPop.dart';
//
@ -171,7 +172,7 @@ class _GamesScreenState extends State<GamesScreen> {
),
),
),
body: ListView(
body: PikaListView(
children: [
...wraps,
...page.page < page.pages

View File

@ -3,6 +3,7 @@ import 'package:pikapika/basic/Method.dart';
import '../basic/Channels.dart';
import 'components/ContentLoading.dart';
import 'components/ListView.dart';
import 'components/RightClickPop.dart';
class ImportFromOffScreen extends StatefulWidget {
@ -58,7 +59,7 @@ class _ImportFromOffScreenState extends State<ImportFromOffScreen> {
appBar: AppBar(
title: const Text('导入'),
),
body: ListView(
body: PikaListView(
children: [
Container(
padding: const EdgeInsets.all(10),

View File

@ -13,6 +13,9 @@ import 'package:pikapika/basic/config/ChooserRoot.dart';
import 'package:pikapika/basic/config/ContentFailedReloadAction.dart';
import 'package:pikapika/basic/config/DownloadAndExportPath.dart';
import 'package:pikapika/basic/config/DownloadThreadCount.dart';
import 'package:pikapika/basic/config/EBookScrolling.dart';
import 'package:pikapika/basic/config/EBookScrollingRange.dart';
import 'package:pikapika/basic/config/EBookScrollingTrigger.dart';
import 'package:pikapika/basic/config/FullScreenAction.dart';
import 'package:pikapika/basic/config/FullScreenUI.dart';
import 'package:pikapika/basic/config/ImageAddress.dart';
@ -119,6 +122,9 @@ class _InitScreenState extends State<InitScreen> {
await initWebDav();
await initImageFilter();
await initReaderBackgroundColor();
await initEBookScrolling();
await initEBookScrollingRange();
await initEBookScrollingTrigger();
String? initUrl;
if (Platform.isAndroid || Platform.isIOS) {

View File

@ -6,6 +6,7 @@ import 'package:pikapika/basic/Method.dart';
import 'package:pikapika/screens/components/ContentBuilder.dart';
import 'package:pikapika/screens/components/ContentLoading.dart';
import 'components/ListView.dart';
import 'components/RightClickPop.dart';
//
@ -55,7 +56,7 @@ class _MigrateScreenState extends State<MigrateScreen> {
(BuildContext context, AsyncSnapshot<dynamic> snapshot) {
switch (_migrate) {
case 0:
return ListView(
return PikaListView(
children: [
Container(
padding: const EdgeInsets.all(10),

View File

@ -3,6 +3,7 @@ import 'package:pikapika/basic/Method.dart';
import 'package:pikapika/screens/components/ContentLoading.dart';
import '../basic/Common.dart';
import 'components/ListView.dart';
import 'components/RightClickPop.dart';
class ModifyPasswordScreen extends StatefulWidget {
@ -49,7 +50,7 @@ class _ModifyPasswordScreenState extends State<ModifyPasswordScreen> {
}
Widget _buildForm() {
return ListView(
return PikaListView(
children: [
const Divider(),
ListTile(

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:pikapika/screens/components/NetworkSetting.dart';
import 'components/ListView.dart';
import 'components/RightClickPop.dart';
class NetworkSettingsScreen extends StatelessWidget {
@ -17,7 +18,7 @@ class NetworkSettingsScreen extends StatelessWidget {
Widget buildScreen(BuildContext context) => Scaffold(
appBar: AppBar(title: const Text('网络设置')),
body: ListView(
body: PikaListView(
children: const [
NetworkSetting(),
],

View File

@ -16,6 +16,7 @@ import '../basic/Navigator.dart';
import '../basic/config/IconLoading.dart';
import '../basic/config/Platform.dart';
import 'PkzComicInfoScreen.dart';
import 'components/ListView.dart';
class PkzArchiveScreen extends StatefulWidget {
final bool holdPkz;
@ -122,7 +123,7 @@ class _PkzArchiveScreenState extends State<PkzArchiveScreen> with RouteAware {
BuildContext context,
AsyncSnapshot snapshot,
) {
return ListView(children: [
return PikaListView(children: [
..._info.comics
.map((e) => GestureDetector(
behavior: HitTestBehavior.opaque,

View File

@ -1,18 +1,15 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:path/path.dart' as p;
import 'package:pikapika/basic/Entities.dart';
import 'package:pikapika/basic/Method.dart';
import 'package:pikapika/screens/PkzReaderScreen.dart';
import 'package:uni_links/uni_links.dart';
import 'package:uri_to_file/uri_to_file.dart';
import '../basic/Common.dart';
import '../basic/Navigator.dart';
import '../basic/config/IconLoading.dart';
import 'PkzArchiveScreen.dart';
import 'components/ListView.dart';
import 'components/PkzComicInfoCard.dart';
class PkzComicInfoScreen extends StatefulWidget {
@ -116,7 +113,7 @@ class _PkzComicInfoScreenState extends State<PkzComicInfoScreen>
widget.pkzComic.title,
),
),
body: ListView(children: [
body: PikaListView(children: [
PkzComicInfoCard(info: widget.pkzComic, pkzPath: widget.pkzPath),
Container(
padding: const EdgeInsets.only(top: 5, bottom: 5),

View File

@ -8,6 +8,7 @@ import 'package:pikapika/screens/AccessKeyReplaceScreen.dart';
import '../basic/config/IconLoading.dart';
import '../basic/config/IsPro.dart';
import 'components/ListView.dart';
class ProScreen extends StatefulWidget {
const ProScreen({Key? key}) : super(key: key);
@ -48,7 +49,7 @@ class _ProScreenState extends State<ProScreen> {
appBar: AppBar(
title: const Text("发电中心"),
),
body: ListView(
body: PikaListView(
children: [
SizedBox(
width: min / 2,
@ -100,13 +101,16 @@ class _ProScreenState extends State<ProScreen> {
ListTile(
title: const Text("我刚才发了电"),
onTap: () async {
final code = await inputString(context, "输入代码");
if (code != null && code.isNotEmpty) {
try {
await method.inputCdKey(code);
defaultToast(context, "SUCCESS");
} catch (e, s) {
defaultToast(context, "FAIL");
var code = await inputString(context, "输入代码");
if (code != null) {
code = code.trim();
if (code.isNotEmpty) {
try {
await method.inputCdKey(code);
defaultToast(context, "SUCCESS");
} catch (e, s) {
defaultToast(context, "FAIL");
}
}
}
await reloadIsPro();

View File

@ -6,6 +6,7 @@ import 'package:pikapika/screens/components/NetworkSetting.dart';
import 'package:pikapika/screens/components/RightClickPop.dart';
import 'components/ContentLoading.dart';
import 'components/ListView.dart';
///
class RegisterScreen extends StatefulWidget {
@ -133,7 +134,7 @@ class _RegisterScreenState extends State<RegisterScreen> {
),
],
),
body: ListView(
body: PikaListView(
children: [
const Divider(),
ListTile(

View File

@ -10,6 +10,8 @@ import 'package:pikapika/basic/config/ChooserRoot.dart';
import 'package:pikapika/basic/config/ContentFailedReloadAction.dart';
import 'package:pikapika/basic/config/DownloadAndExportPath.dart';
import 'package:pikapika/basic/config/DownloadThreadCount.dart';
import 'package:pikapika/basic/config/EBookScrollingRange.dart';
import 'package:pikapika/basic/config/EBookScrollingTrigger.dart';
import 'package:pikapika/basic/config/ExportRename.dart';
import 'package:pikapika/basic/config/FullScreenAction.dart';
import 'package:pikapika/basic/config/FullScreenUI.dart';
@ -24,17 +26,18 @@ import 'package:pikapika/basic/config/ReaderDirection.dart';
import 'package:pikapika/basic/config/ReaderSliderPosition.dart';
import 'package:pikapika/basic/config/ReaderType.dart';
import 'package:pikapika/basic/config/ShadowCategories.dart';
import 'package:pikapika/basic/config/ShadowCategoriesMode.dart';
import 'package:pikapika/basic/config/ShowCommentAtDownload.dart';
import 'package:pikapika/basic/config/Themes.dart';
import 'package:pikapika/basic/config/TimeOffsetHour.dart';
import 'package:pikapika/basic/config/VolumeController.dart';
import 'package:pikapika/basic/config/ShadowCategoriesMode.dart';
import 'package:pikapika/screens/components/NetworkSetting.dart';
import 'package:pikapika/screens/components/RightClickPop.dart';
import '../basic/config/Authentication.dart';
import '../basic/config/CategoriesColumnCount.dart';
import '../basic/config/DownloadCachePath.dart';
import '../basic/config/EBookScrolling.dart';
import '../basic/config/HiddenFdIcon.dart';
import '../basic/config/ImageFilter.dart';
import '../basic/config/UsingRightClickPop.dart';
@ -66,175 +69,158 @@ class _SettingsScreenState extends State<SettingsScreen> {
);
}
late var _index = 0;
Widget buildScreen(BuildContext context) {
final List<_IconAndWidgets> iaws = [
_IconAndWidgets(Icons.lan, [
const Padding(padding: EdgeInsets.only(top: 15)),
const Divider(),
const ListTile(
subtitle: Text("网络&账户"),
),
const Divider(),
widget.hiddenAccountInfo
? Container()
: ListTile(
onTap: () async {
Navigator.push(
context,
mixRoute(
builder: (context) => const ModifyPasswordScreen(),
),
);
},
title: const Text('修改密码'),
),
const Divider(),
const NetworkSetting(),
const Padding(padding: EdgeInsets.only(top: 15)),
const Divider(),
const ListTile(
subtitle: Text("同步"),
),
...webDavSettings(context),
const Divider(),
const Padding(padding: EdgeInsets.only(top: 15)),
]),
_IconAndWidgets(Icons.ad_units, [
const Padding(padding: EdgeInsets.only(top: 15)),
const Divider(),
const ListTile(
subtitle: Text("系统&界面"),
),
const Divider(),
ListTile(
onTap: () async {
if (androidNightModeDisplay) {
Navigator.push(
context,
mixRoute(builder: (context) => const ThemeScreen()),
);
} else {
chooseLightTheme(context);
}
},
title: const Text('主题'),
),
fullScreenUISetting(),
noAnimationSetting(),
iconLoadingSetting(),
categoriesColumnCountSetting(),
willPopNoticeSetting(),
hiddenFdIconSetting(),
pagerActionSetting(),
contentFailedReloadActionSetting(),
timeZoneSetting(),
fontSetting(),
usingRightClickPopSetting(),
const Divider(),
androidDisplayModeSetting(),
androidSecureFlagSetting(),
authenticationSetting(),
const Divider(),
migrate(context),
const Divider(),
const Padding(padding: EdgeInsets.only(top: 15)),
]),
_IconAndWidgets(Icons.confirmation_num_rounded, [
const Divider(),
const Padding(padding: EdgeInsets.only(top: 15)),
const Divider(),
const ListTile(
subtitle: Text("内容&阅读器"),
),
const Divider(),
shadowCategoriesModeSetting(),
shadowCategoriesSetting(),
const Divider(),
qualitySetting(),
readerTypeSetting(),
readerDirectionSetting(),
readerSliderPositionSetting(),
autoFullScreenSetting(),
fullScreenActionSetting(),
volumeControllerSetting(),
keyboardControllerSetting(),
const Divider(),
imageFilterSetting(),
readerBackgroundColorSetting(),
const Divider(),
const Padding(padding: EdgeInsets.only(top: 15)),
]),
_IconAndWidgets(Icons.download, [
const Padding(padding: EdgeInsets.only(top: 15)),
const Divider(),
const ListTile(
subtitle: Text("下载&缓存"),
),
const Divider(),
ListTile(
title: const Text("启动Web服务器"),
subtitle: const Text("让局域网内的设备通过浏览器看下载的漫画"),
onTap: (){
Navigator.of(context).push(
mixRoute(
builder: (BuildContext context) =>
const WebServerScreen(),
),
);
},
),
const Divider(),
autoCleanSecSetting(),
ListTile(
onTap: () {
Navigator.push(
context,
mixRoute(builder: (context) => const CleanScreen()),
);
},
title: const Text('清除缓存'),
),
const Divider(),
chooserRootSetting(),
downloadThreadCountSetting(),
downloadAndExportPathSetting(),
showCommentAtDownloadSetting(),
exportRenameSetting(),
const Divider(),
downloadCachePathSetting(),
importViewLogFromOff(),
const Divider(),
const Padding(padding: EdgeInsets.only(top: 15)),
]),
];
var i = 0;
return Scaffold(
appBar: AppBar(
title: const Text('设置'),
actions: [
...iaws.map(
(e) {
final idx = i;
return Opacity(
child: IconButton(
onPressed: () {
setState(() {
_index = idx;
});
},
icon: Icon(e.icon),
),
opacity: i++ == _index ? 1 : .75,
);
},
)
],
),
body: ListView(
children: iaws[_index].widgets,
body: SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(
children: [
ExpansionTile(
leading: Icon(Icons.energy_savings_leaf),
title: Text('界面'),
children: [
const Divider(),
...themeWidgets(context, setState),
const Divider(),
pagerActionSetting(),
contentFailedReloadActionSetting(),
willPopNoticeSetting(),
categoriesColumnCountSetting(),
const Divider(),
timeZoneSetting(),
fontSetting(),
fullScreenUISetting(),
usingRightClickPopSetting(),
hiddenFdIconSetting(),
const Divider(),
androidDisplayModeSetting(),
androidSecureFlagSetting(),
authenticationSetting(),
const Divider(),
iconLoadingSetting(),
eBookScrollingSetting(),
eBookScrollingRangeSetting(),
eBookScrollingTriggerSetting(),
const Divider(),
],
),
ExpansionTile(
leading: Icon(Icons.lan),
title: Text('网络'),
children: [
const Divider(),
const NetworkSetting(),
],
),
ExpansionTile(
leading: Icon(Icons.backup),
title: Text('同步'),
children: [
const Divider(),
...webDavSettings(context),
],
),
ExpansionTile(
leading: Icon(Icons.manage_accounts),
title: Text('账户'),
children: [
const Divider(),
widget.hiddenAccountInfo
? Container()
: ListTile(
onTap: () async {
Navigator.push(
context,
mixRoute(
builder: (context) =>
const ModifyPasswordScreen(),
),
);
},
title: const Text('修改密码'),
),
],
),
ExpansionTile(
leading: Icon(Icons.dangerous),
title: Text('封印'),
children: [
const Divider(),
shadowCategoriesModeSetting(),
shadowCategoriesSetting(),
],
),
ExpansionTile(
leading: Icon(Icons.menu_book_outlined),
title: Text('阅读'),
children: [
const Divider(),
qualitySetting(),
readerTypeSetting(),
readerDirectionSetting(),
readerSliderPositionSetting(),
autoFullScreenSetting(),
fullScreenActionSetting(),
volumeControllerSetting(),
keyboardControllerSetting(),
const Divider(),
noAnimationSetting(),
imageFilterSetting(),
readerBackgroundColorSetting(),
],
),
ExpansionTile(
leading: Icon(Icons.download),
title: Text('下载'),
children: [
const Divider(),
ListTile(
title: const Text("启动Web服务器"),
subtitle: const Text("让局域网内的设备通过浏览器看下载的漫画"),
onTap: () {
Navigator.of(context).push(
mixRoute(
builder: (BuildContext context) =>
const WebServerScreen(),
),
);
},
),
const Divider(),
chooserRootSetting(),
downloadThreadCountSetting(),
downloadAndExportPathSetting(),
showCommentAtDownloadSetting(),
exportRenameSetting(),
],
),
ExpansionTile(
leading: Icon(Icons.ad_units),
title: Text('系统'),
children: [
const Divider(),
autoCleanSecSetting(),
ListTile(
onTap: () {
Navigator.push(
context,
mixRoute(builder: (context) => const CleanScreen()),
);
},
title: const Text('清除缓存'),
),
const Divider(),
migrate(context),
const Divider(),
downloadCachePathSetting(),
importViewLogFromOff(),
],
),
],
),
),
);
}

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import '../basic/config/Themes.dart';
import 'components/ListView.dart';
import 'components/RightClickPop.dart';
class ThemeScreen extends StatefulWidget {
@ -23,45 +24,45 @@ class _ThemeScreenState extends State<ThemeScreen> {
Widget buildScreen(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("主题设置")),
body: ListView(
children: [
const Divider(),
ListTile(
onTap: () async {
await chooseLightTheme(context);
setState(() {});
},
title: const Text('主题'),
subtitle: Text(currentLightThemeName()),
),
const Divider(),
...androidNightModeDisplay
? [
SwitchListTile(
title: const Text("深色模式下使用不同的主题"),
value: androidNightMode,
onChanged: (value) async {
await setAndroidNightMode(value);
setState(() {});
}),
]
: [],
const Divider(),
...androidNightModeDisplay && androidNightMode
? [
ListTile(
onTap: () async {
await chooseDarkTheme(context);
setState(() {});
},
title: const Text('主题 (深色模式)'),
subtitle: Text(currentDarkThemeName()),
),
]
: [],
const Divider(),
],
body: PikaListView(
children: themeWidgets(context, setState),
),
);
}
}
List<Widget> themeWidgets(BuildContext context, void Function(VoidCallback fn) setState) {
return [
ListTile(
onTap: () async {
await chooseLightTheme(context);
setState(() {});
},
title: const Text('主题'),
subtitle: Text(currentLightThemeName()),
),
...androidNightModeDisplay
? [
SwitchListTile(
title: const Text("深色模式下使用不同的主题"),
value: androidNightMode,
onChanged: (value) async {
await setAndroidNightMode(value);
setState(() {});
}),
]
: [],
...androidNightModeDisplay && androidNightMode
? [
ListTile(
onTap: () async {
await chooseDarkTheme(context);
setState(() {});
},
title: const Text('主题 (深色模式)'),
subtitle: Text(currentDarkThemeName()),
),
]
: [],
];
}

View File

@ -10,6 +10,7 @@ import '../basic/Entities.dart';
import '../basic/config/IconLoading.dart';
import 'ComicInfoScreen.dart';
import 'components/Images.dart';
import 'components/ListView.dart';
//
class ViewLogsScreen extends StatefulWidget {
@ -137,7 +138,7 @@ class _ViewLogsScreenState extends State<ViewLogsScreen> {
onPressed: _clearAll, icon: const Icon(Icons.auto_delete)),
],
),
body: ListView(
body: PikaListView(
physics: _scrollPhysics,
controller: _scrollController,
children: entries.toList(),

View File

@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import '../basic/Method.dart';
import 'components/ContentError.dart';
import 'components/ContentLoading.dart';
import 'components/ListView.dart';
import 'components/RightClickPop.dart';
class WebServerScreen extends StatefulWidget {
@ -52,7 +53,7 @@ class _WebServerScreenState extends State<WebServerScreen> {
if (snapshot.connectionState != ConnectionState.done) {
return const ContentLoading(label: '加载中');
}
return ListView(
return PikaListView(
children: [
Container(
padding: const EdgeInsets.all(8),

View File

@ -12,6 +12,7 @@ import 'package:pikapika/basic/config/ShadowCategoriesMode.dart';
import 'ComicInfoCard.dart';
import 'Images.dart';
import 'LinkToComicInfo.dart';
import 'ListView.dart';
class ComicListController {
_ComicListState? _state;
@ -113,7 +114,7 @@ class _ComicListState extends State<ComicList> {
}
Widget _buildInfoCardList() {
return ListView(
return PikaListView(
controller: widget.scrollController,
physics: const AlwaysScrollableScrollPhysics(),
children: [
@ -229,19 +230,24 @@ class _ComicListState extends State<ComicList> {
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;
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;
}
}
return false;
},
).reduce((value, element) => value || element);
shadow = true;
break;
}
if (shadow) {
tmp.add(
Container(
@ -317,7 +323,7 @@ class _ComicListState extends State<ComicList> {
tmp = [];
}
//
return ListView(
return PikaListView(
controller: widget.scrollController,
physics: const AlwaysScrollableScrollPhysics(),
padding: EdgeInsets.only(top: gap, bottom: gap),
@ -338,19 +344,24 @@ class _ComicListState extends State<ComicList> {
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;
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;
}
}
return false;
},
).reduce((value, element) => value || element);
shadow = true;
break;
}
if (shadow) {
tmp.add(
Container(
@ -455,7 +466,7 @@ class _ComicListState extends State<ComicList> {
tmp = [];
}
//
return ListView(
return PikaListView(
controller: widget.scrollController,
physics: const AlwaysScrollableScrollPhysics(),
padding: EdgeInsets.only(top: gap, bottom: gap),

View File

@ -0,0 +1,95 @@
import 'package:flutter/material.dart';
import 'package:pikapika/basic/config/EBookScrolling.dart';
import '../../basic/config/EBookScrollingRange.dart';
import '../../basic/config/EBookScrollingTrigger.dart';
class PikaListView extends StatefulWidget {
final EdgeInsets? padding;
final ScrollController? controller;
final List<Widget> children;
final ScrollPhysics? physics;
const PikaListView({
Key? key,
required this.children,
this.controller,
this.padding,
this.physics,
}) : super(key: key);
@override
State<StatefulWidget> createState() => _PikaListViewState();
}
class _PikaListViewState extends State<PikaListView> {
late ScrollController _privateController;
@override
void initState() {
if (widget.controller == null) {
_privateController = ScrollController();
}
super.initState();
}
@override
void dispose() {
if (widget.controller == null) {
_privateController.dispose();
}
super.dispose();
}
ScrollController get _controller => widget.controller ?? _privateController;
double _y = 0;
@override
Widget build(BuildContext context) {
if (!eBookScrolling) {
return ListView(
children: widget.children,
controller: _controller,
padding: widget.padding,
physics: widget.physics,
);
}
return LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return GestureDetector(
onPanDown: (details) {
_y = 0;
},
onPanUpdate: (details) {
_y += details.delta.dy;
},
onPanEnd: (details) {
final lmPoints =
(MediaQuery.of(context).devicePixelRatio * (160 / 2.54));
final double centimeters = _y / lmPoints;
late double off;
if (centimeters < -eBookScrollingTrigger) {
off = _controller.offset +
eBookScrollingRange * constraints.maxHeight;
off = off.clamp(0, _controller.position.maxScrollExtent);
_controller.jumpTo(off);
_controller.notifyListeners();
} else if (centimeters > eBookScrollingTrigger) {
off = _controller.offset -
eBookScrollingRange * constraints.maxHeight;
off = off.clamp(0, _controller.position.maxScrollExtent);
_controller.jumpTo(off);
_controller.notifyListeners();
}
},
child: ListView(
physics: const NeverScrollableScrollPhysics(),
children: widget.children,
controller: _controller,
padding: widget.padding,
),
);
},
);
}
}

View File

@ -133,10 +133,10 @@ packages:
dependency: "direct main"
description:
name: file_picker
sha256: dd328189f2f4ccea042bb5b382d5e981691cc74b5a3429b9317bff2b19704489
sha256: dcde5ad1a0cebcf3715ea3f24d0db1888bf77027a26c77d7779e8ef63b8ade62
url: "https://pub.dev"
source: hosted
version: "5.2.8"
version: "5.2.9"
filesystem_picker:
dependency: "direct main"
description:
@ -566,10 +566,10 @@ packages:
dependency: transitive
description:
name: url_launcher_android
sha256: dd729390aa936bf1bdf5cd1bc7468ff340263f80a2c4f569416507667de8e3c8
sha256: a52628068d282d01a07cd86e6ba99e497aa45ce8c91159015b2416907d78e411
url: "https://pub.dev"
source: hosted
version: "6.0.26"
version: "6.0.27"
url_launcher_ios:
dependency: transitive
description:

View File

@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.7.3+18
version: 1.7.4+19
environment:
sdk: ">=2.12.0 <3.0.0"