opt: pages

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2024-12-15 23:26:27 +08:00
parent 5a69e6abb0
commit 3852e21571
13 changed files with 234 additions and 278 deletions

View File

@@ -127,6 +127,9 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
if (Platform.isIOS || Platform.isAndroid) {
StatusBarControl.setHidden(false, animation: StatusBarAnimation.FADE);
}
for (int index = 0; index < widget.sources.length; index++) {
CachedNetworkImageProvider(_getActualUrl(index)).evict();
}
super.dispose();
}
@@ -206,6 +209,10 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
}
}
String _getActualUrl(int index) => _thumbList[index] && _quality != 100
? '${widget.sources[index]}@${_quality}q.webp'
: widget.sources[index];
@override
Widget build(BuildContext context) {
return Stack(
@@ -252,7 +259,7 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
index == currentIndex,
_enablePageView,
)
: _itemBuilder(widget.sources, index),
: _itemBuilder(index),
);
},
),
@@ -358,17 +365,15 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
Share.shareXFiles([XFile(path)], subject: imgUrl);
}
Widget _itemBuilder(sources, index) {
Widget _itemBuilder(index) {
return Center(
child: Hero(
tag: sources[index],
tag: widget.sources[index],
child: CachedNetworkImage(
fadeInDuration: const Duration(milliseconds: 0),
fadeOutDuration: const Duration(milliseconds: 0),
imageUrl: _thumbList[index] && _quality != 100
? '${sources[index]}@${_quality}q.webp'
: sources[index],
fit: BoxFit.contain,
imageUrl: _getActualUrl(index),
// fit: BoxFit.contain,
progressIndicatorBuilder: (context, url, progress) {
return Center(
child: SizedBox(
@@ -377,13 +382,13 @@ class _InteractiveviewerGalleryState extends State<InteractiveviewerGallery>
),
);
},
errorListener: (value) {
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() {
_thumbList[index] = false;
});
});
},
// errorListener: (value) {
// WidgetsBinding.instance.addPostFrameCallback((_) {
// setState(() {
// _thumbList[index] = false;
// });
// });
// },
),
),
);

View File

@@ -88,12 +88,12 @@ class NetworkImgLayer extends StatelessWidget {
placeholder: (BuildContext context, String url) =>
placeholder(context),
imageBuilder: imageBuilder,
errorListener: (value) {
thumbnail = false;
if (context.mounted) {
(context as Element).markNeedsBuild();
}
},
// errorListener: (value) {
// thumbnail = false;
// if (context.mounted) {
// (context as Element).markNeedsBuild();
// }
// },
),
),
)

View File

@@ -4,18 +4,12 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:PiliPalaX/http/index.dart';
import 'package:PiliPalaX/models/github/latest.dart';
import 'package:PiliPalaX/pages/setting/controller.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPalaX/utils/utils.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../utils/cache_manage.dart';
const String _sourceCodeUrl = 'https://github.com/bggRGjQaUbCoE/PiliPalaX';
const String _originSourceCodeUrl = 'https://github.com/guozhigq/pilipala';
const String _upstreamUrl = 'https://github.com/orz12/PiliPalaX';
class AboutPage extends StatefulWidget {
const AboutPage({super.key});
@@ -25,6 +19,11 @@ class AboutPage extends StatefulWidget {
class _AboutPageState extends State<AboutPage> {
final AboutController _aboutController = Get.put(AboutController());
static const String _sourceCodeUrl =
'https://github.com/bggRGjQaUbCoE/PiliPalaX';
static const String _originSourceCodeUrl =
'https://github.com/guozhigq/pilipala';
static const String _upstreamUrl = 'https://github.com/orz12/PiliPalaX';
@override
void initState() {
@@ -115,13 +114,13 @@ class _AboutPageState extends State<AboutPage> {
color: Theme.of(context).colorScheme.outlineVariant,
),
ListTile(
onTap: () => _aboutController.githubUrl(_sourceCodeUrl),
onTap: () => Utils.launchURL(_sourceCodeUrl),
leading: const Icon(Icons.code),
title: const Text('Source Code'),
subtitle: Text(_sourceCodeUrl, style: subTitleStyle),
),
ListTile(
onTap: () => _aboutController.githubUrl(_originSourceCodeUrl),
onTap: () => Utils.launchURL(_originSourceCodeUrl),
leading: const Icon(Icons.code),
title: const Text('Origin'),
subtitle: Text(
@@ -130,7 +129,7 @@ class _AboutPageState extends State<AboutPage> {
),
),
ListTile(
onTap: () => _aboutController.githubUrl(_upstreamUrl),
onTap: () => Utils.launchURL(_upstreamUrl),
leading: const Icon(Icons.code),
title: const Text('Upstream'),
subtitle: Text(
@@ -139,7 +138,23 @@ class _AboutPageState extends State<AboutPage> {
),
),
ListTile(
onTap: () => _aboutController.feedback(context),
onTap: () {
showDialog(
context: context,
builder: (context) {
return SimpleDialog(
clipBehavior: Clip.hardEdge,
title: const Text('问题反馈'),
children: [
ListTile(
title: const Text('GitHub Issue'),
onTap: () => Utils.launchURL('$_sourceCodeUrl/issues'),
),
],
);
},
);
},
leading: const Icon(Icons.feedback_outlined),
title: const Text('问题反馈'),
trailing: Icon(
@@ -149,7 +164,9 @@ class _AboutPageState extends State<AboutPage> {
),
),
ListTile(
onTap: () => _aboutController.logs(),
onTap: () {
Get.toNamed('/logs');
},
leading: const Icon(Icons.bug_report_outlined),
title: const Text('错误日志'),
trailing: Icon(Icons.arrow_forward, size: 16, color: outline),
@@ -257,22 +274,26 @@ class _AboutPageState extends State<AboutPage> {
child: const Text('取消'),
),
TextButton(
onPressed: () {
onPressed: () async {
Get.back();
GStorage.setting.clear();
GStorage.video.clear();
await Future.wait([
GStorage.setting.clear(),
GStorage.video.clear(),
]);
SmartDialog.showToast('重置成功');
},
child: const Text('重置可导出的设置'),
),
TextButton(
onPressed: () {
onPressed: () async {
Get.back();
GStorage.userInfo.clear();
GStorage.setting.clear();
GStorage.localCache.clear();
GStorage.video.clear();
GStorage.historyWord.clear();
await Future.wait([
GStorage.userInfo.clear(),
GStorage.setting.clear(),
GStorage.localCache.clear(),
GStorage.video.clear(),
GStorage.historyWord.clear(),
]);
SmartDialog.showToast('重置成功');
},
child: const Text('重置所有数据(含登录信息)'),
@@ -298,7 +319,6 @@ class AboutController extends GetxController {
RxBool isUpdate = true.obs;
RxBool isLoading = true.obs;
LatestDataModel? data;
// RxInt count = 0.obs;
RxString cacheSize = ''.obs;
@override
@@ -330,91 +350,21 @@ class AboutController extends GetxController {
currentVersion.value = "${currentInfo.version}+$buildNumber";
}
// 获取远程版本
Future getRemoteApp() async {
var result = await Request().get(Api.latestApp, extra: {'ua': 'pc'});
if (result.data.isEmpty) {
SmartDialog.showToast('检查更新失败github接口未返回数据请检查网络');
return false;
} else if (result.data[0] == null) {
SmartDialog.showToast('检查更新失败github接口返回如下内容\n${result.data}');
return false;
}
data = LatestDataModel.fromJson(result.data[0]);
remoteAppInfo = data;
remoteVersion.value = data!.tagName!;
isUpdate.value =
Utils.needUpdate(currentVersion.value, remoteVersion.value);
isLoading.value = false;
}
// 跳转下载/本地更新
Future onUpdate() async {
if (data != null) {
Utils.matchVersion(data);
}
}
// 跳转github
githubUrl(String url) {
launchUrl(
Uri.parse(url),
mode: LaunchMode.externalApplication,
);
}
githubRelease() {
launchUrl(
Uri.parse('$_sourceCodeUrl/release'),
mode: LaunchMode.externalApplication,
);
}
// 问题反馈
feedback(BuildContext context) async {
await showDialog(
context: context,
builder: (context) {
return SimpleDialog(
clipBehavior: Clip.hardEdge,
title: const Text('问题反馈'),
children: [
ListTile(
title: const Text('GitHub Issue'),
onTap: () => launchUrl(
Uri.parse('$_sourceCodeUrl/issues'),
// 系统自带浏览器打开
mode: LaunchMode.externalApplication,
),
),
// ListTile(
// title: const Text('腾讯兔小巢'),
// onTap: () => launchUrl(
// Uri.parse('https://support.qq.com/embed/phone/637735'),
// // 系统自带浏览器打开
// mode: LaunchMode.externalApplication,
// ),
// ),
],
);
},
);
}
// 日志
logs() {
Get.toNamed('/logs');
}
// tapOnVersion() {
// if (settingController.hiddenSettingUnlocked.value) {
// SmartDialog.showToast('您已解锁开发人员选项, 无需再次操作');
// return;
// }
// count.value++;
// if (count.value == 5) {
// setting.put(SettingBoxKey.hiddenSettingUnlocked, true);
// SmartDialog.showToast('恭喜您发现了开发人员选项!');
// // 获取远程版本
// Future getRemoteApp() async {
// var result = await Request().get(Api.latestApp, extra: {'ua': 'pc'});
// if (result.data.isEmpty) {
// SmartDialog.showToast('检查更新失败github接口未返回数据请检查网络');
// return false;
// } else if (result.data[0] == null) {
// SmartDialog.showToast('检查更新失败github接口返回如下内容\n${result.data}');
// return false;
// }
// data = LatestDataModel.fromJson(result.data[0]);
// remoteAppInfo = data;
// remoteVersion.value = data!.tagName!;
// isUpdate.value =
// Utils.needUpdate(currentVersion.value, remoteVersion.value);
// isLoading.value = false;
// }
}

View File

@@ -126,7 +126,6 @@ abstract class ReplyController extends CommonController {
sortType = ReplySortType.time;
mode = Mode.MAIN_LIST_TIME;
break;
default:
}
sortTypeTitle.value = sortType.titles;
sortTypeLabel.value = sortType.labels;

View File

@@ -225,28 +225,28 @@ class _UpPanelState extends State<UpPanel> {
}
}
class _SliverHeaderDelegate extends SliverPersistentHeaderDelegate {
_SliverHeaderDelegate({required this.height, required this.child});
// class _SliverHeaderDelegate extends SliverPersistentHeaderDelegate {
// _SliverHeaderDelegate({required this.height, required this.child});
final double height;
final Widget child;
// final double height;
// final Widget child;
@override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return child;
}
// @override
// Widget build(
// BuildContext context, double shrinkOffset, bool overlapsContent) {
// return child;
// }
@override
double get maxExtent => height;
// @override
// double get maxExtent => height;
@override
double get minExtent => height;
// @override
// double get minExtent => height;
@override
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) =>
true;
}
// @override
// bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) =>
// true;
// }
class UpPanelSkeleton extends StatelessWidget {
const UpPanelSkeleton({super.key});

View File

@@ -111,21 +111,21 @@ class _FollowPageState extends State<FollowPage> {
}
}
class _FakeAPI {
static const List<String> _kOptions = <String>[
'aardvark',
'bobcat',
'chameleon',
];
// Searches the options, but injects a fake "network" delay.
static Future<Iterable<String>> search(String query) async {
await Future<void>.delayed(
const Duration(seconds: 1)); // Fake 1 second delay.
if (query == '') {
return const Iterable<String>.empty();
}
return _kOptions.where((String option) {
return option.contains(query.toLowerCase());
});
}
}
// class _FakeAPI {
// static const List<String> _kOptions = <String>[
// 'aardvark',
// 'bobcat',
// 'chameleon',
// ];
// // Searches the options, but injects a fake "network" delay.
// static Future<Iterable<String>> search(String query) async {
// await Future<void>.delayed(
// const Duration(seconds: 1)); // Fake 1 second delay.
// if (query == '') {
// return const Iterable<String>.empty();
// }
// return _kOptions.where((String option) {
// return option.contains(query.toLowerCase());
// });
// }
// }

View File

@@ -120,12 +120,15 @@ class _LoginPageState extends State<LoginPage> {
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
child: Text(_loginPageCtr.codeInfo.value['data']?['url'] ?? "",
style: Theme.of(context).textTheme.labelSmall!.copyWith(
child: Text(
_loginPageCtr.codeInfo.value['data']?['url'] ?? "",
style: Theme.of(context).textTheme.labelSmall!.copyWith(
color: Theme.of(context)
.colorScheme
.onSurface
.withOpacity(0.4))),
.withOpacity(0.4),
),
),
),
)),
Padding(

View File

@@ -1527,37 +1527,37 @@ class VideoDetailController extends GetxController
},
);
List<SegmentType> _actionType2SegmentType(ActionType actionType) {
return switch (actionType) {
ActionType.skip => [
SegmentType.sponsor,
SegmentType.selfpromo,
SegmentType.interaction,
SegmentType.intro,
SegmentType.outro,
SegmentType.preview,
SegmentType.filler,
],
ActionType.mute => [
SegmentType.sponsor,
SegmentType.selfpromo,
SegmentType.interaction,
SegmentType.intro,
SegmentType.outro,
SegmentType.preview,
SegmentType.music_offtopic,
SegmentType.filler,
],
ActionType.full => [
SegmentType.sponsor,
SegmentType.selfpromo,
SegmentType.exclusive_access,
],
ActionType.poi => [
SegmentType.poi_highlight,
],
};
}
// List<SegmentType> _actionType2SegmentType(ActionType actionType) {
// return switch (actionType) {
// ActionType.skip => [
// SegmentType.sponsor,
// SegmentType.selfpromo,
// SegmentType.interaction,
// SegmentType.intro,
// SegmentType.outro,
// SegmentType.preview,
// SegmentType.filler,
// ],
// ActionType.mute => [
// SegmentType.sponsor,
// SegmentType.selfpromo,
// SegmentType.interaction,
// SegmentType.intro,
// SegmentType.outro,
// SegmentType.preview,
// SegmentType.music_offtopic,
// SegmentType.filler,
// ],
// ActionType.full => [
// SegmentType.sponsor,
// SegmentType.selfpromo,
// SegmentType.exclusive_access,
// ],
// ActionType.poi => [
// SegmentType.poi_highlight,
// ],
// };
// }
List<ActionType> _segmentType2ActionType(SegmentType segmentType) {
return switch (segmentType) {

View File

@@ -191,6 +191,7 @@ class LiveMessageStream {
for (final server in servers) {
try {
return await WebSocket.connect(server);
// ignore: empty_catches
} catch (e) {}
}
throw Exception("all servers connect failed");

View File

@@ -301,20 +301,20 @@ class PiliScheme {
// https | m.bilibili.com | /bangumi/play/ss39708
// final String scheme = value.scheme!;
final String host = value.host;
final String? path = value.path;
final String path = value.path;
Map<String, String> query = value.queryParameters;
RegExp regExp = RegExp(r'^((www\.)|(m\.))?bilibili\.com$');
if (regExp.hasMatch(host)) {
debugPrint('bilibili.com');
} else if (host.contains('live')) {
int roomId = int.parse(path!.split('/').last);
int roomId = int.parse(path.split('/').last);
Utils.toDupNamed(
'/liveRoom?roomid=$roomId',
arguments: {'liveItem': null, 'heroTag': roomId.toString()},
);
return;
} else if (host.contains('space')) {
var mid = path!.split('/').last;
var mid = path.split('/').last;
Utils.toDupNamed('/member?mid=$mid', arguments: {'face': ''});
return;
} else if (host == 'b23.tv') {
@@ -352,79 +352,77 @@ class PiliScheme {
return;
}
if (path != null) {
List<String> pathPart = path.split('/');
if (pathPart.length < 3) {
List<String> pathPart = path.split('/');
if (pathPart.length < 3) {
Utils.toDupNamed(
'/webviewnew',
parameters: {'url': value.toString()},
);
return;
}
final String area = pathPart[1] == 'mobile' ? pathPart[2] : pathPart[1];
switch (area) {
case 'bangumi':
debugPrint('番剧');
for (var pathSegment in pathPart) {
if (pathSegment.startsWith('ss')) {
bangumiPush(matchNum(pathSegment).first, null);
break;
} else if (pathSegment.startsWith('ep')) {
bangumiPush(null, matchNum(pathSegment).first);
break;
}
}
break;
case 'video':
debugPrint('投稿');
final Map<String, dynamic> map = IdUtils.matchAvorBv(input: path);
if (map.containsKey('AV')) {
videoPush(map['AV']! as int, null);
} else if (map.containsKey('BV')) {
videoPush(null, map['BV'] as String);
} else {
SmartDialog.showToast('投稿匹配失败');
}
break;
case 'read':
debugPrint('专栏');
late String id;
if (query['id'] != null) {
id = 'cv${matchNum(query['id']!).first}';
} else {
id = 'cv${matchNum(path).firstOrNull}';
}
Utils.toDupNamed('/htmlRender', parameters: {
'url': value.toString(),
'title': '',
'id': id,
'dynamicType': 'read'
});
break;
case 'space':
debugPrint('个人空间');
Utils.toDupNamed(
'/webviewnew',
parameters: {'url': value.toString()},
);
return;
}
final String area = pathPart[1] == 'mobile' ? pathPart[2] : pathPart[1];
switch (area) {
case 'bangumi':
debugPrint('番剧');
for (var pathSegment in pathPart) {
if (pathSegment.startsWith('ss')) {
bangumiPush(matchNum(pathSegment).first, null);
break;
} else if (pathSegment.startsWith('ep')) {
bangumiPush(null, matchNum(pathSegment).first);
break;
}
}
break;
case 'video':
debugPrint('投稿');
final Map<String, dynamic> map = IdUtils.matchAvorBv(input: path);
if (map.containsKey('AV')) {
videoPush(map['AV']! as int, null);
} else if (map.containsKey('BV')) {
videoPush(null, map['BV'] as String);
} else {
SmartDialog.showToast('投稿匹配失败');
}
break;
case 'read':
debugPrint('专栏');
late String id;
if (query['id'] != null) {
id = 'cv${matchNum(query['id']!).first}';
} else {
id = 'cv${matchNum(path).firstOrNull}';
}
Utils.toDupNamed('/htmlRender', parameters: {
'url': value.toString(),
'title': '',
'id': id,
'dynamicType': 'read'
});
break;
case 'space':
debugPrint('个人空间');
'/member?mid=${pathPart[1] == 'mobile' ? pathPart.getOrNull(3) : pathPart.getOrNull(2)}',
arguments: {'face': ''});
break;
default:
var res = IdUtils.matchAvorBv(input: area.split('?').first);
if (res.containsKey('AV')) {
videoPush(res['AV']! as int, null);
} else if (res.containsKey('BV')) {
videoPush(null, res['BV'] as String);
} else {
SmartDialog.showToast('未知路径或匹配错误:$value,先采用浏览器打开');
Utils.toDupNamed(
'/member?mid=${pathPart[1] == 'mobile' ? pathPart.getOrNull(3) : pathPart.getOrNull(2)}',
arguments: {'face': ''});
break;
default:
var res = IdUtils.matchAvorBv(input: area.split('?').first);
if (res.containsKey('AV')) {
videoPush(res['AV']! as int, null);
} else if (res.containsKey('BV')) {
videoPush(null, res['BV'] as String);
} else {
SmartDialog.showToast('未知路径或匹配错误:$value,先采用浏览器打开');
Utils.toDupNamed(
'/webviewnew',
parameters: {
'url': value.toString(),
'type': 'url',
'pageTitle': ''
},
);
}
}
'/webviewnew',
parameters: {
'url': value.toString(),
'type': 'url',
'pageTitle': ''
},
);
}
}
}

View File

@@ -1,5 +1,5 @@
// 订阅者回调签名
typedef void EventCallback(arg);
typedef EventCallback = void Function(dynamic arg);
class EventBus {
// 私有构造函数

View File

@@ -53,7 +53,7 @@ extension StringExt on String {
String get http2https => replaceFirst(RegExp("^http://"), "https://");
}
extension boolExt on bool {
extension BoolExt on bool {
bool get not => !this;
}