mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
Merge remote-tracking branch 'upstream/main'
This commit is contained in:
201
.github/workflows/main.yml
vendored
201
.github/workflows/main.yml
vendored
@@ -1,84 +1,157 @@
|
|||||||
name: build_apk
|
name: Pilipala Release
|
||||||
|
|
||||||
# action事件触发
|
# action事件触发
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
# push tag时触发
|
# push tag时触发
|
||||||
tags:
|
tags:
|
||||||
- 'v*.*.*'
|
- "v*.*.*"
|
||||||
|
|
||||||
# 可以有多个jobs
|
# 可以有多个jobs
|
||||||
jobs:
|
jobs:
|
||||||
build_apk:
|
android:
|
||||||
# 运行环境 ubuntu-latest window-latest mac-latest
|
# 运行环境 ubuntu-latest window-latest mac-latest
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
# 每个jobs中可以有多个steps
|
# 每个jobs中可以有多个steps
|
||||||
steps:
|
steps:
|
||||||
- name: 代码迁出
|
- name: 代码迁出
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: 构建Java环境
|
- name: 构建Java环境
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: "zulu"
|
distribution: "zulu"
|
||||||
java-version: "17"
|
java-version: "17"
|
||||||
token: ${{secrets.GIT_TOKEN}}
|
token: ${{secrets.GIT_TOKEN}}
|
||||||
|
|
||||||
- name: 检查缓存
|
- name: 检查缓存
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v2
|
||||||
id: cache-flutter
|
id: cache-flutter
|
||||||
with:
|
with:
|
||||||
path: /root/flutter-sdk # Flutter SDK 的路径
|
path: /root/flutter-sdk # Flutter SDK 的路径
|
||||||
key: ${{ runner.os }}-flutter-${{ hashFiles('**/pubspec.lock') }}
|
key: ${{ runner.os }}-flutter-${{ hashFiles('**/pubspec.lock') }}
|
||||||
|
|
||||||
- name: 安装Flutter
|
- name: 安装Flutter
|
||||||
if: steps.cache-flutter.outputs.cache-hit != 'true'
|
if: steps.cache-flutter.outputs.cache-hit != 'true'
|
||||||
uses: subosito/flutter-action@v2
|
uses: subosito/flutter-action@v2
|
||||||
with:
|
with:
|
||||||
flutter-version: 3.16.5
|
flutter-version: 3.16.5
|
||||||
channel: any
|
channel: any
|
||||||
|
|
||||||
- name: 下载项目依赖
|
- name: 下载项目依赖
|
||||||
run: flutter pub get
|
run: flutter pub get
|
||||||
|
|
||||||
- name: 解码生成 jks
|
- name: 解码生成 jks
|
||||||
run: echo $KEYSTORE_BASE64 | base64 -di > android/app/vvex.jks
|
run: echo $KEYSTORE_BASE64 | base64 -di > android/app/vvex.jks
|
||||||
env:
|
env:
|
||||||
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
|
KEYSTORE_BASE64: ${{ secrets.KEYSTORE_BASE64 }}
|
||||||
|
|
||||||
- name: flutter build apk
|
- name: flutter build apk
|
||||||
# 对应 android/app/build.gradle signingConfigs中的配置项
|
run: flutter build apk --release --split-per-abi
|
||||||
run: flutter build apk --release --split-per-abi
|
env:
|
||||||
env:
|
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
|
||||||
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
|
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
|
||||||
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
|
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD}}
|
||||||
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD}}
|
|
||||||
|
|
||||||
- name: 获取版本号
|
- name: flutter build apk
|
||||||
id: version
|
run: flutter build apk --release
|
||||||
run: echo "version=${GITHUB_REF#refs/tags/v}" >>$GITHUB_OUTPUT
|
env:
|
||||||
|
KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
|
||||||
|
KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
|
||||||
|
KEY_PASSWORD: ${{ secrets.KEY_PASSWORD}}
|
||||||
|
|
||||||
# - name: 获取当前日期
|
- name: 获取版本号
|
||||||
# id: date
|
id: version
|
||||||
# run: echo "date=$(date +'%m%d')" >>$GITHUB_OUTPUT
|
run: echo "version=${GITHUB_REF#refs/tags/v}" >>$GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: 重命名应用 Pili-arm64-v8a-*.*.*.0101.apk
|
# - name: 获取当前日期
|
||||||
run: |
|
# id: date
|
||||||
# DATE=${{ steps.date.outputs.date }}
|
# run: echo "date=$(date +'%m%d')" >>$GITHUB_OUTPUT
|
||||||
for file in build/app/outputs/flutter-apk/app-*-release.apk; do
|
|
||||||
if [[ $file =~ app-(.*)-release.apk ]]; then
|
|
||||||
new_file_name="build/app/outputs/flutter-apk/Pili-${BASH_REMATCH[1]}-${{ steps.version.outputs.version }}.apk"
|
|
||||||
mv "$file" "$new_file_name"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
- name: 构建和发布release
|
- name: 重命名应用
|
||||||
uses: ncipollo/release-action@v1
|
run: |
|
||||||
with:
|
# DATE=${{ steps.date.outputs.date }}
|
||||||
# release title
|
for file in build/app/outputs/flutter-apk/app-*.apk; do
|
||||||
name: v${{ steps.version.outputs.version }}
|
if [[ $file =~ app-(.?*)release.apk ]]; then
|
||||||
artifacts: "build/app/outputs/flutter-apk/Pili-*.apk"
|
new_file_name="build/app/outputs/flutter-apk/Pili-${BASH_REMATCH[1]}${{ steps.version.outputs.version }}.apk"
|
||||||
bodyFile: "change_log/${{steps.version.outputs.version}}.md"
|
mv "$file" "$new_file_name"
|
||||||
token: ${{ secrets.GIT_TOKEN }}
|
fi
|
||||||
allowUpdates: true
|
done
|
||||||
|
|
||||||
|
- name: 上传
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: Pilipala-Release
|
||||||
|
path: |
|
||||||
|
build/app/outputs/flutter-apk/Pili-*.apk
|
||||||
|
|
||||||
|
iOS:
|
||||||
|
runs-on: macos-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: 代码迁出
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: 安装Flutter
|
||||||
|
if: steps.cache-flutter.outputs.cache-hit != 'true'
|
||||||
|
uses: subosito/flutter-action@v2.10.0
|
||||||
|
with:
|
||||||
|
cache: true
|
||||||
|
flutter-version: 3.16.5
|
||||||
|
|
||||||
|
- name: flutter build ipa
|
||||||
|
run: |
|
||||||
|
flutter build ios --release --no-codesign
|
||||||
|
ln -sf ./build/ios/iphoneos Payload
|
||||||
|
zip -r9 app.ipa Payload/runner.app
|
||||||
|
|
||||||
|
- name: 获取版本号
|
||||||
|
id: version
|
||||||
|
run: echo "version=${GITHUB_REF#refs/tags/v}" >>$GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: 重命名应用
|
||||||
|
run: |
|
||||||
|
DATE=${{ steps.date.outputs.date }}
|
||||||
|
for file in app.ipa; do
|
||||||
|
new_file_name="build/Pili-${{ steps.version.outputs.version }}.ipa"
|
||||||
|
mv "$file" "$new_file_name"
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: 上传
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
if-no-files-found: error
|
||||||
|
name: Pilipala-Release
|
||||||
|
path: |
|
||||||
|
build/Pili-*.ipa
|
||||||
|
|
||||||
|
upload:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
needs:
|
||||||
|
- android
|
||||||
|
- iOS
|
||||||
|
steps:
|
||||||
|
- uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
name: Pilipala-Release
|
||||||
|
path: ./Pilipala-Release
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: sudo apt-get install tree -y
|
||||||
|
|
||||||
|
- name: Get version
|
||||||
|
id: version
|
||||||
|
run: echo "version=${GITHUB_REF#refs/tags/v}" >>$GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Upload Release
|
||||||
|
uses: ncipollo/release-action@v1
|
||||||
|
with:
|
||||||
|
name: v${{ steps.version.outputs.version }}
|
||||||
|
token: ${{ secrets.GIT_TOKEN }}
|
||||||
|
omitBodyDuringUpdate: true
|
||||||
|
omitNameDuringUpdate: true
|
||||||
|
omitPrereleaseDuringUpdate: true
|
||||||
|
allowUpdates: true
|
||||||
|
artifacts: Pilipala-Release/*
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ android {
|
|||||||
applicationId "com.guozhigq.pilipala"
|
applicationId "com.guozhigq.pilipala"
|
||||||
// You can update the following values to match your application needs.
|
// You can update the following values to match your application needs.
|
||||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||||
// minSdkVersion flutter.minSdkVersion
|
|
||||||
targetSdkVersion flutter.targetSdkVersion
|
targetSdkVersion flutter.targetSdkVersion
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
|
|||||||
16
change_log/1.0.18.0130.md
Normal file
16
change_log/1.0.18.0130.md
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
## 1.0.18
|
||||||
|
|
||||||
|
|
||||||
|
### 功能
|
||||||
|
|
||||||
|
|
||||||
|
### 修复
|
||||||
|
|
||||||
|
|
||||||
|
### 优化
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
更多更新日志可在Github上查看
|
||||||
|
问题反馈、功能建议请查看「关于」页面。
|
||||||
15
change_log/1.0.19.0131.md
Normal file
15
change_log/1.0.19.0131.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
## 1.0.19
|
||||||
|
|
||||||
|
|
||||||
|
### 修复
|
||||||
|
+ 视频404、评论加载错误
|
||||||
|
+ bvav转换
|
||||||
|
|
||||||
|
### 优化
|
||||||
|
+ 视频详情页内存占用
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
更多更新日志可在Github上查看
|
||||||
|
问题反馈、功能建议请查看「关于」页面。
|
||||||
@@ -13,8 +13,13 @@ PODS:
|
|||||||
- device_info_plus (0.0.1):
|
- device_info_plus (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- Flutter (1.0.0)
|
- Flutter (1.0.0)
|
||||||
|
- flutter_mailer (0.0.1):
|
||||||
|
- Flutter
|
||||||
- flutter_volume_controller (0.0.1):
|
- flutter_volume_controller (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- fluttertoast (0.0.2):
|
||||||
|
- Flutter
|
||||||
|
- Toast
|
||||||
- FMDB (2.7.5):
|
- FMDB (2.7.5):
|
||||||
- FMDB/standard (= 2.7.5)
|
- FMDB/standard (= 2.7.5)
|
||||||
- FMDB/standard (2.7.5)
|
- FMDB/standard (2.7.5)
|
||||||
@@ -49,6 +54,7 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- system_proxy (0.0.1):
|
- system_proxy (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- Toast (4.1.0)
|
||||||
- url_launcher_ios (0.0.1):
|
- url_launcher_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- volume_controller (0.0.1):
|
- volume_controller (0.0.1):
|
||||||
@@ -68,7 +74,9 @@ DEPENDENCIES:
|
|||||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
|
||||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||||
- Flutter (from `Flutter`)
|
- Flutter (from `Flutter`)
|
||||||
|
- flutter_mailer (from `.symlinks/plugins/flutter_mailer/ios`)
|
||||||
- flutter_volume_controller (from `.symlinks/plugins/flutter_volume_controller/ios`)
|
- flutter_volume_controller (from `.symlinks/plugins/flutter_volume_controller/ios`)
|
||||||
|
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
|
||||||
- gt3_flutter_plugin (from `.symlinks/plugins/gt3_flutter_plugin/ios`)
|
- gt3_flutter_plugin (from `.symlinks/plugins/gt3_flutter_plugin/ios`)
|
||||||
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
|
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
|
||||||
- media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`)
|
- media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`)
|
||||||
@@ -93,6 +101,7 @@ SPEC REPOS:
|
|||||||
- FMDB
|
- FMDB
|
||||||
- GT3Captcha-iOS
|
- GT3Captcha-iOS
|
||||||
- ReachabilitySwift
|
- ReachabilitySwift
|
||||||
|
- Toast
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
appscheme:
|
appscheme:
|
||||||
@@ -109,8 +118,12 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/device_info_plus/ios"
|
:path: ".symlinks/plugins/device_info_plus/ios"
|
||||||
Flutter:
|
Flutter:
|
||||||
:path: Flutter
|
:path: Flutter
|
||||||
|
flutter_mailer:
|
||||||
|
:path: ".symlinks/plugins/flutter_mailer/ios"
|
||||||
flutter_volume_controller:
|
flutter_volume_controller:
|
||||||
:path: ".symlinks/plugins/flutter_volume_controller/ios"
|
:path: ".symlinks/plugins/flutter_volume_controller/ios"
|
||||||
|
fluttertoast:
|
||||||
|
:path: ".symlinks/plugins/fluttertoast/ios"
|
||||||
gt3_flutter_plugin:
|
gt3_flutter_plugin:
|
||||||
:path: ".symlinks/plugins/gt3_flutter_plugin/ios"
|
:path: ".symlinks/plugins/gt3_flutter_plugin/ios"
|
||||||
media_kit_libs_ios_video:
|
media_kit_libs_ios_video:
|
||||||
@@ -156,7 +169,9 @@ SPEC CHECKSUMS:
|
|||||||
connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a
|
connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a
|
||||||
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
|
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
|
||||||
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
||||||
|
flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83
|
||||||
flutter_volume_controller: e4d5832f08008180f76e30faf671ffd5a425e529
|
flutter_volume_controller: e4d5832f08008180f76e30faf671ffd5a425e529
|
||||||
|
fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265
|
||||||
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
||||||
gt3_flutter_plugin: bfa1f26e9a09dc00401514be5ed437f964cabf23
|
gt3_flutter_plugin: bfa1f26e9a09dc00401514be5ed437f964cabf23
|
||||||
GT3Captcha-iOS: 5e3b1077834d8a9d6f4d64a447a30af3e14affe6
|
GT3Captcha-iOS: 5e3b1077834d8a9d6f4d64a447a30af3e14affe6
|
||||||
@@ -173,6 +188,7 @@ SPEC CHECKSUMS:
|
|||||||
sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
|
sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
|
||||||
status_bar_control: 7c84146799e6a076315cc1550f78ef53aae3e446
|
status_bar_control: 7c84146799e6a076315cc1550f78ef53aae3e446
|
||||||
system_proxy: bec1a5c5af67dd3e3ebf43979400a8756c04cc44
|
system_proxy: bec1a5c5af67dd3e3ebf43979400a8756c04cc44
|
||||||
|
Toast: ec33c32b8688982cecc6348adeae667c1b9938da
|
||||||
url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b
|
url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b
|
||||||
volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9
|
volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9
|
||||||
wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47
|
wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47
|
||||||
|
|||||||
@@ -181,8 +181,14 @@ class Request {
|
|||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
} on DioException catch (e) {
|
} on DioException catch (e) {
|
||||||
print('get error: $e');
|
Response errResponse = Response(
|
||||||
return Future.error(await ApiInterceptor.dioError(e));
|
data: {
|
||||||
|
'message': await ApiInterceptor.dioError(e)
|
||||||
|
}, // 将自定义 Map 数据赋值给 Response 的 data 属性
|
||||||
|
statusCode: 200,
|
||||||
|
requestOptions: RequestOptions(),
|
||||||
|
);
|
||||||
|
return errResponse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,8 +209,14 @@ class Request {
|
|||||||
// print('post success: ${response.data}');
|
// print('post success: ${response.data}');
|
||||||
return response;
|
return response;
|
||||||
} on DioException catch (e) {
|
} on DioException catch (e) {
|
||||||
print('post error: $e');
|
Response errResponse = Response(
|
||||||
return Future.error(await ApiInterceptor.dioError(e));
|
data: {
|
||||||
|
'message': await ApiInterceptor.dioError(e)
|
||||||
|
}, // 将自定义 Map 数据赋值给 Response 的 data 属性
|
||||||
|
statusCode: 200,
|
||||||
|
requestOptions: RequestOptions(),
|
||||||
|
);
|
||||||
|
return errResponse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import 'package:dio/dio.dart';
|
|||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import '../utils/storage.dart';
|
import '../utils/storage.dart';
|
||||||
// import 'package:get/get.dart' hide Response;
|
|
||||||
|
|
||||||
class ApiInterceptor extends Interceptor {
|
class ApiInterceptor extends Interceptor {
|
||||||
@override
|
@override
|
||||||
@@ -71,35 +70,28 @@ class ApiInterceptor extends Interceptor {
|
|||||||
return '发送请求超时,请检查网络设置';
|
return '发送请求超时,请检查网络设置';
|
||||||
case DioExceptionType.unknown:
|
case DioExceptionType.unknown:
|
||||||
final String res = await checkConnect();
|
final String res = await checkConnect();
|
||||||
return '$res \n 网络异常,请稍后重试!';
|
return '$res,网络异常!';
|
||||||
// default:
|
|
||||||
// return 'Dio异常';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<String> checkConnect() async {
|
static Future<String> checkConnect() async {
|
||||||
final ConnectivityResult connectivityResult =
|
final ConnectivityResult connectivityResult =
|
||||||
await Connectivity().checkConnectivity();
|
await Connectivity().checkConnectivity();
|
||||||
if (connectivityResult == ConnectivityResult.mobile) {
|
switch (connectivityResult) {
|
||||||
return 'connected with mobile network';
|
case ConnectivityResult.mobile:
|
||||||
} else if (connectivityResult == ConnectivityResult.wifi) {
|
return '正在使用移动流量';
|
||||||
return 'connected with wifi network';
|
case ConnectivityResult.wifi:
|
||||||
} else if (connectivityResult == ConnectivityResult.ethernet) {
|
return '正在使用wifi';
|
||||||
// I am connected to a ethernet network.
|
case ConnectivityResult.ethernet:
|
||||||
return '';
|
return '正在使用局域网';
|
||||||
} else if (connectivityResult == ConnectivityResult.vpn) {
|
case ConnectivityResult.vpn:
|
||||||
// I am connected to a vpn network.
|
return '正在使用代理网络';
|
||||||
// Note for iOS and macOS:
|
case ConnectivityResult.other:
|
||||||
// There is no separate network interface type for [vpn].
|
return '正在使用其他网络';
|
||||||
// It returns [other] on any device (also simulator)
|
case ConnectivityResult.none:
|
||||||
return '';
|
return '未连接到任何网络';
|
||||||
} else if (connectivityResult == ConnectivityResult.other) {
|
default:
|
||||||
// I am connected to a network which is not in the above mentioned networks.
|
return '';
|
||||||
return '';
|
|
||||||
} else if (connectivityResult == ConnectivityResult.none) {
|
|
||||||
return 'not connected to any network';
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import 'package:pilipala/utils/data.dart';
|
|||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
import 'package:media_kit/media_kit.dart'; // Provides [Player], [Media], [Playlist] etc.
|
import 'package:media_kit/media_kit.dart'; // Provides [Player], [Media], [Playlist] etc.
|
||||||
import 'package:pilipala/utils/recommend_filter.dart';
|
import 'package:pilipala/utils/recommend_filter.dart';
|
||||||
|
import 'package:catcher_2/catcher_2.dart';
|
||||||
|
import './services/loggeer.dart';
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
@@ -40,7 +42,32 @@ void main() async {
|
|||||||
Request();
|
Request();
|
||||||
await Request.setCookie();
|
await Request.setCookie();
|
||||||
RecommendFilter();
|
RecommendFilter();
|
||||||
runApp(const MyApp());
|
|
||||||
|
// 异常捕获 logo记录
|
||||||
|
final Catcher2Options debugConfig = Catcher2Options(
|
||||||
|
SilentReportMode(),
|
||||||
|
[
|
||||||
|
FileHandler(await getLogsPath()),
|
||||||
|
ConsoleHandler(
|
||||||
|
enableDeviceParameters: false,
|
||||||
|
enableApplicationParameters: false,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
final Catcher2Options releaseConfig = Catcher2Options(
|
||||||
|
SilentReportMode(),
|
||||||
|
[FileHandler(await getLogsPath())],
|
||||||
|
);
|
||||||
|
|
||||||
|
Catcher2(
|
||||||
|
debugConfig: debugConfig,
|
||||||
|
releaseConfig: releaseConfig,
|
||||||
|
runAppFunction: () {
|
||||||
|
runApp(const MyApp());
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// 小白条、导航栏沉浸
|
// 小白条、导航栏沉浸
|
||||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
|
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
|
||||||
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
|
SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle(
|
||||||
|
|||||||
@@ -133,6 +133,11 @@ class _AboutPageState extends State<AboutPage> {
|
|||||||
title: const Text('赞助'),
|
title: const Text('赞助'),
|
||||||
trailing: Icon(Icons.arrow_forward_ios, size: 16, color: outline),
|
trailing: Icon(Icons.arrow_forward_ios, size: 16, color: outline),
|
||||||
),
|
),
|
||||||
|
ListTile(
|
||||||
|
onTap: () => _aboutController.logs(),
|
||||||
|
title: const Text('错误日志'),
|
||||||
|
trailing: Icon(Icons.arrow_forward_ios, size: 16, color: outline),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -260,4 +265,9 @@ class AboutController extends GetxController {
|
|||||||
mode: LaunchMode.externalApplication,
|
mode: LaunchMode.externalApplication,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 日志
|
||||||
|
logs() {
|
||||||
|
Get.toNamed('/logs');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
// 内容
|
// 内容
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/common/widgets/badge.dart';
|
import 'package:pilipala/common/widgets/badge.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
import 'package:pilipala/models/dynamics/result.dart';
|
import 'package:pilipala/models/dynamics/result.dart';
|
||||||
@@ -80,7 +81,7 @@ class _ContentState extends State<Content> {
|
|||||||
height: height,
|
height: height,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
height > maxHeight
|
height > Get.size.height * 0.9
|
||||||
? const PBadge(
|
? const PBadge(
|
||||||
text: '长图',
|
text: '长图',
|
||||||
right: 8,
|
right: 8,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/common/constants.dart';
|
import 'package:pilipala/common/constants.dart';
|
||||||
import 'package:pilipala/common/widgets/badge.dart';
|
import 'package:pilipala/common/widgets/badge.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
@@ -87,7 +88,7 @@ Widget picWidget(item, context) {
|
|||||||
childAspectRatio: aspectRatio,
|
childAspectRatio: aspectRatio,
|
||||||
children: list,
|
children: list,
|
||||||
),
|
),
|
||||||
if (len == 1 && origAspectRatio < 0.4)
|
if (len == 1 && height > Get.size.height * 0.9)
|
||||||
const PBadge(
|
const PBadge(
|
||||||
text: '长图',
|
text: '长图',
|
||||||
top: null,
|
top: null,
|
||||||
|
|||||||
@@ -63,13 +63,16 @@ class HomeController extends GetxController with GetTickerProviderStateMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setTabConfig() async {
|
void setTabConfig() async {
|
||||||
defaultTabs = tabsConfig;
|
defaultTabs = [...tabsConfig];
|
||||||
tabbarSort = settingStorage.get(SettingBoxKey.tabbarSort,
|
tabbarSort = settingStorage.get(SettingBoxKey.tabbarSort,
|
||||||
defaultValue: ['live', 'rcmd', 'hot', 'bangumi']);
|
defaultValue: ['live', 'rcmd', 'hot', 'bangumi']);
|
||||||
|
defaultTabs.retainWhere(
|
||||||
|
(item) => tabbarSort.contains((item['type'] as TabType).id));
|
||||||
|
defaultTabs.sort((a, b) => tabbarSort
|
||||||
|
.indexOf((a['type'] as TabType).id)
|
||||||
|
.compareTo(tabbarSort.indexOf((b['type'] as TabType).id)));
|
||||||
|
|
||||||
tabs.value = defaultTabs
|
tabs.value = defaultTabs;
|
||||||
.where((i) => tabbarSort.contains((i['type'] as TabType).id))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
if (tabbarSort.contains(TabType.rcmd.id)) {
|
if (tabbarSort.contains(TabType.rcmd.id)) {
|
||||||
initialIndex.value = tabbarSort.indexOf(TabType.rcmd.id);
|
initialIndex.value = tabbarSort.indexOf(TabType.rcmd.id);
|
||||||
|
|||||||
@@ -25,16 +25,17 @@ Widget searchArticlePanel(BuildContext context, ctr, list) {
|
|||||||
padding: const EdgeInsets.fromLTRB(
|
padding: const EdgeInsets.fromLTRB(
|
||||||
StyleString.safeSpace, 5, StyleString.safeSpace, 5),
|
StyleString.safeSpace, 5, StyleString.safeSpace, 5),
|
||||||
child: LayoutBuilder(builder: (context, boxConstraints) {
|
child: LayoutBuilder(builder: (context, boxConstraints) {
|
||||||
double width = (boxConstraints.maxWidth -
|
final double width = (boxConstraints.maxWidth -
|
||||||
StyleString.cardSpace *
|
StyleString.cardSpace *
|
||||||
6 /
|
6 /
|
||||||
MediaQuery.textScalerOf(context).scale(2.0));
|
MediaQuery.textScalerOf(context).scale(1.0)) /
|
||||||
|
2;
|
||||||
return Container(
|
return Container(
|
||||||
constraints: const BoxConstraints(minHeight: 88),
|
constraints: const BoxConstraints(minHeight: 88),
|
||||||
height: width / StyleString.aspectRatio,
|
height: width / StyleString.aspectRatio,
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: <Widget>[
|
||||||
if (list[index].imageUrls != null &&
|
if (list[index].imageUrls != null &&
|
||||||
list[index].imageUrls.isNotEmpty)
|
list[index].imageUrls.isNotEmpty)
|
||||||
AspectRatio(
|
AspectRatio(
|
||||||
|
|||||||
@@ -22,6 +22,17 @@ class _TabbarSetPageState extends State<TabbarSetPage> {
|
|||||||
defaultTabs = tabsConfig;
|
defaultTabs = tabsConfig;
|
||||||
tabbarSort = settingStorage.get(SettingBoxKey.tabbarSort,
|
tabbarSort = settingStorage.get(SettingBoxKey.tabbarSort,
|
||||||
defaultValue: ['live', 'rcmd', 'hot', 'bangumi']);
|
defaultValue: ['live', 'rcmd', 'hot', 'bangumi']);
|
||||||
|
// 对 tabData 进行排序
|
||||||
|
defaultTabs.sort((a, b) {
|
||||||
|
int indexA = tabbarSort.indexOf((a['type'] as TabType).id);
|
||||||
|
int indexB = tabbarSort.indexOf((b['type'] as TabType).id);
|
||||||
|
|
||||||
|
// 如果类型在 sortOrder 中不存在,则放在末尾
|
||||||
|
if (indexA == -1) indexA = tabbarSort.length;
|
||||||
|
if (indexB == -1) indexB = tabbarSort.length;
|
||||||
|
|
||||||
|
return indexA.compareTo(indexB);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveEdit() {
|
void saveEdit() {
|
||||||
|
|||||||
201
lib/pages/setting/pages/logs.dart
Normal file
201
lib/pages/setting/pages/logs.dart
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:pilipala/common/widgets/no_data.dart';
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
import '../../../services/loggeer.dart';
|
||||||
|
|
||||||
|
class LogsPage extends StatefulWidget {
|
||||||
|
const LogsPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<LogsPage> createState() => _LogsPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LogsPageState extends State<LogsPage> {
|
||||||
|
late File logsPath;
|
||||||
|
late String fileContent;
|
||||||
|
List logsContent = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
getPath();
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void getPath() async {
|
||||||
|
logsPath = await getLogsPath();
|
||||||
|
fileContent = await logsPath.readAsString();
|
||||||
|
logsContent = await parseLogs(fileContent);
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<Map<String, dynamic>>> parseLogs(String fileContent) async {
|
||||||
|
const String splitToken =
|
||||||
|
'======================================================================';
|
||||||
|
List contentList = fileContent.split(splitToken).map((item) {
|
||||||
|
return item
|
||||||
|
.replaceAll(
|
||||||
|
'============================== CATCHER 2 LOG ==============================',
|
||||||
|
'Pilipala错误日志 \n ********************')
|
||||||
|
.replaceAll('DEVICE INFO', '设备信息')
|
||||||
|
.replaceAll('APP INFO', '应用信息')
|
||||||
|
.replaceAll('ERROR', '错误信息')
|
||||||
|
.replaceAll('STACK TRACE', '错误堆栈');
|
||||||
|
}).toList();
|
||||||
|
List<Map<String, dynamic>> result = [];
|
||||||
|
for (String i in contentList) {
|
||||||
|
DateTime? date;
|
||||||
|
String body = i
|
||||||
|
.split("\n")
|
||||||
|
.map((l) {
|
||||||
|
if (l.startsWith("Crash occurred on")) {
|
||||||
|
date = DateTime.parse(
|
||||||
|
l.split("Crash occurred on")[1].trim().split('.')[0],
|
||||||
|
);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
})
|
||||||
|
.where((dynamic l) => l.replaceAll("\n", "").trim().isNotEmpty)
|
||||||
|
.join("\n");
|
||||||
|
if (date != null || body != '') {
|
||||||
|
result.add({'date': date, 'body': body, 'expand': false});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.reversed.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void copyLogs() async {
|
||||||
|
await Clipboard.setData(ClipboardData(text: fileContent));
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(content: Text('复制成功')),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void feedback() {
|
||||||
|
launchUrl(
|
||||||
|
Uri.parse('https://github.com/guozhigq/pilipala/issues'),
|
||||||
|
// 系统自带浏览器打开
|
||||||
|
mode: LaunchMode.externalApplication,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearLogsHandle() async {
|
||||||
|
if (await clearLogs()) {
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(content: Text('已清空')),
|
||||||
|
);
|
||||||
|
logsContent = [];
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
centerTitle: false,
|
||||||
|
titleSpacing: 0,
|
||||||
|
title: Text('日志', style: Theme.of(context).textTheme.titleMedium),
|
||||||
|
actions: [
|
||||||
|
PopupMenuButton<String>(
|
||||||
|
onSelected: (String type) {
|
||||||
|
// 处理菜单项选择的逻辑
|
||||||
|
switch (type) {
|
||||||
|
case 'copy':
|
||||||
|
copyLogs();
|
||||||
|
break;
|
||||||
|
case 'feedback':
|
||||||
|
feedback();
|
||||||
|
break;
|
||||||
|
case 'clear':
|
||||||
|
clearLogsHandle();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
|
||||||
|
const PopupMenuItem<String>(
|
||||||
|
value: 'copy',
|
||||||
|
child: Text('复制日志'),
|
||||||
|
),
|
||||||
|
const PopupMenuItem<String>(
|
||||||
|
value: 'feedback',
|
||||||
|
child: Text('错误反馈'),
|
||||||
|
),
|
||||||
|
const PopupMenuItem<String>(
|
||||||
|
value: 'clear',
|
||||||
|
child: Text('清空日志'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: logsContent.isNotEmpty
|
||||||
|
? ListView.builder(
|
||||||
|
itemCount: logsContent.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final log = logsContent[index];
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Text(
|
||||||
|
log['date'].toString(),
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextButton.icon(
|
||||||
|
onPressed: () async {
|
||||||
|
await Clipboard.setData(
|
||||||
|
ClipboardData(text: log['body']),
|
||||||
|
);
|
||||||
|
if (context.mounted) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
'已将 ${log['date'].toString()} 复制至剪贴板',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.copy_outlined, size: 16),
|
||||||
|
label: const Text('复制'),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Card(
|
||||||
|
elevation: 1,
|
||||||
|
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(12.0),
|
||||||
|
child: SelectableText(log['body']),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Divider(indent: 12, endIndent: 12),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: const CustomScrollView(
|
||||||
|
slivers: <Widget>[
|
||||||
|
NoData(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -256,7 +256,12 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
|
|||||||
// 请求错误
|
// 请求错误
|
||||||
return HttpError(
|
return HttpError(
|
||||||
errMsg: data['msg'],
|
errMsg: data['msg'],
|
||||||
fn: () => setState(() {}),
|
fn: () {
|
||||||
|
setState(() {
|
||||||
|
_futureBuilderFuture =
|
||||||
|
_videoReplyController.queryReplyList();
|
||||||
|
});
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -784,7 +784,7 @@ InlineSpan buildContent(
|
|||||||
height: height,
|
height: height,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
height > maxHeight
|
height > Get.size.height * 0.9
|
||||||
? const PBadge(
|
? const PBadge(
|
||||||
text: '长图',
|
text: '长图',
|
||||||
right: 8,
|
right: 8,
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/http/msg.dart';
|
import 'package:pilipala/http/msg.dart';
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import 'dart:convert';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:get/get_core/src/get_main.dart';
|
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
import 'package:pilipala/utils/utils.dart';
|
import 'package:pilipala/utils/utils.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
@@ -53,12 +52,13 @@ class ChatItem extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
bool isOwner =
|
bool isOwner =
|
||||||
item.senderUid == GStrorage.userInfo.get('userInfoCache').mid;
|
item.senderUid == GStrorage.userInfo.get('userInfoCache').mid;
|
||||||
bool isPic = item.msgType == MsgType.pic; // 图片
|
|
||||||
bool isText = item.msgType == MsgType.text; // 文本
|
bool isPic = item.msgType == MsgType.pic.value; // 图片
|
||||||
|
bool isText = item.msgType == MsgType.text.value; // 文本
|
||||||
// bool isArchive = item.msgType == 11; // 投稿
|
// bool isArchive = item.msgType == 11; // 投稿
|
||||||
// bool isArticle = item.msgType == 12; // 专栏
|
// bool isArticle = item.msgType == 12; // 专栏
|
||||||
bool isRevoke = item.msgType == MsgType.revoke; // 撤回消息
|
bool isRevoke = item.msgType == MsgType.revoke.value; // 撤回消息
|
||||||
bool isShareV2 = item.msgType == MsgType.share_v2;
|
bool isShareV2 = item.msgType == MsgType.share_v2.value;
|
||||||
bool isSystem =
|
bool isSystem =
|
||||||
item.msgType == 18 || item.msgType == 10 || item.msgType == 13;
|
item.msgType == 18 || item.msgType == 10 || item.msgType == 13;
|
||||||
dynamic content = item.content ?? '';
|
dynamic content = item.content ?? '';
|
||||||
@@ -72,7 +72,7 @@ class ChatItem extends StatelessWidget {
|
|||||||
var text = content['content'];
|
var text = content['content'];
|
||||||
if (e_infos != null) {
|
if (e_infos != null) {
|
||||||
final List<InlineSpan> children = [];
|
final List<InlineSpan> children = [];
|
||||||
Map<String,String> emojiMap = {};
|
Map<String, String> emojiMap = {};
|
||||||
for (var e in e_infos!) {
|
for (var e in e_infos!) {
|
||||||
emojiMap[e['text']] = e['url'];
|
emojiMap[e['text']] = e['url'];
|
||||||
}
|
}
|
||||||
@@ -83,18 +83,22 @@ class ChatItem extends StatelessWidget {
|
|||||||
if (emojiMap.containsKey(emojiKey)) {
|
if (emojiMap.containsKey(emojiKey)) {
|
||||||
children.add(WidgetSpan(
|
children.add(WidgetSpan(
|
||||||
child: NetworkImgLayer(
|
child: NetworkImgLayer(
|
||||||
width: 18, height: 18,
|
width: 18,
|
||||||
src: emojiMap[emojiKey]!,),
|
height: 18,
|
||||||
|
src: emojiMap[emojiKey]!,
|
||||||
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
onNonMatch: (String text) {
|
onNonMatch: (String text) {
|
||||||
children.add(TextSpan(text: text, style: TextStyle(
|
children.add(TextSpan(
|
||||||
color: textColor(context),
|
text: text,
|
||||||
letterSpacing: 0.6,
|
style: TextStyle(
|
||||||
height: 1.5,
|
color: textColor(context),
|
||||||
)));
|
letterSpacing: 0.6,
|
||||||
|
height: 1.5,
|
||||||
|
)));
|
||||||
return '';
|
return '';
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -123,11 +127,13 @@ class ChatItem extends StatelessWidget {
|
|||||||
return SystemNotice2(item: item);
|
return SystemNotice2(item: item);
|
||||||
case MsgType.notify_text:
|
case MsgType.notify_text:
|
||||||
return Text(
|
return Text(
|
||||||
jsonDecode(content['content']).map((m) => m['text'] as String).join("\n"),
|
jsonDecode(content['content'])
|
||||||
|
.map((m) => m['text'] as String)
|
||||||
|
.join("\n"),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
letterSpacing: 0.6,
|
letterSpacing: 0.6,
|
||||||
height: 5,
|
height: 5,
|
||||||
color: Theme.of(context).colorScheme.outline.withOpacity(0.8)
|
color: Theme.of(context).colorScheme.outline.withOpacity(0.8),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
case MsgType.text:
|
case MsgType.text:
|
||||||
@@ -166,9 +172,11 @@ class ChatItem extends StatelessWidget {
|
|||||||
Text(
|
Text(
|
||||||
content['title'],
|
content['title'],
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
letterSpacing: 0.6,
|
letterSpacing: 0.6,
|
||||||
height: 1.5,
|
height: 1.5,
|
||||||
color: textColor(context), fontWeight: FontWeight.bold),
|
color: textColor(context),
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 1),
|
const SizedBox(height: 1),
|
||||||
Text(
|
Text(
|
||||||
@@ -186,9 +194,11 @@ class ChatItem extends StatelessWidget {
|
|||||||
return Text(
|
return Text(
|
||||||
content['content'] ?? content.toString(),
|
content['content'] ?? content.toString(),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
letterSpacing: 0.6,
|
letterSpacing: 0.6,
|
||||||
height: 1.5,
|
height: 1.5,
|
||||||
color: textColor(context), fontWeight: FontWeight.bold),
|
color: textColor(context),
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -278,7 +278,8 @@ class PlPlayerController {
|
|||||||
danmakuDurationVal =
|
danmakuDurationVal =
|
||||||
localCache.get(LocalCacheKey.danmakuDuration, defaultValue: 4.0);
|
localCache.get(LocalCacheKey.danmakuDuration, defaultValue: 4.0);
|
||||||
// 描边粗细
|
// 描边粗细
|
||||||
strokeWidth = localCache.get(LocalCacheKey.strokeWidth, defaultValue: 1.5);
|
strokeWidth =
|
||||||
|
localCache.get(LocalCacheKey.strokeWidth, defaultValue: 1.5);
|
||||||
playRepeat = PlayRepeat.values.toList().firstWhere(
|
playRepeat = PlayRepeat.values.toList().firstWhere(
|
||||||
(e) =>
|
(e) =>
|
||||||
e.value ==
|
e.value ==
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:pilipala/pages/setting/pages/logs.dart';
|
||||||
|
|
||||||
import '../pages/about/index.dart';
|
import '../pages/about/index.dart';
|
||||||
import '../pages/blacklist/index.dart';
|
import '../pages/blacklist/index.dart';
|
||||||
@@ -153,6 +154,8 @@ class Routes {
|
|||||||
// 用户专栏
|
// 用户专栏
|
||||||
CustomGetPage(
|
CustomGetPage(
|
||||||
name: '/memberSeasons', page: () => const MemberSeasonsPage()),
|
name: '/memberSeasons', page: () => const MemberSeasonsPage()),
|
||||||
|
// 日志
|
||||||
|
CustomGetPage(name: '/logs', page: () => const LogsPage()),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
56
lib/services/loggeer.dart
Normal file
56
lib/services/loggeer.dart
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
// final _loggerFactory =
|
||||||
|
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:logger/logger.dart';
|
||||||
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
|
|
||||||
|
final _loggerFactory = PiliLogger();
|
||||||
|
|
||||||
|
PiliLogger getLogger<T>() {
|
||||||
|
return _loggerFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PiliLogger extends Logger {
|
||||||
|
PiliLogger() : super();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void log(Level level, dynamic message,
|
||||||
|
{Object? error, StackTrace? stackTrace, DateTime? time}) async {
|
||||||
|
if (level == Level.error) {
|
||||||
|
String dir = (await getApplicationDocumentsDirectory()).path;
|
||||||
|
// 创建logo文件
|
||||||
|
final String filename = p.join(dir, ".pili_logs");
|
||||||
|
// 添加至文件末尾
|
||||||
|
await File(filename).writeAsString(
|
||||||
|
"**${DateTime.now()}** \n $message \n $stackTrace",
|
||||||
|
mode: FileMode.writeOnlyAppend,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
super.log(level, "$message", error: error, stackTrace: stackTrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<File> getLogsPath() async {
|
||||||
|
String dir = (await getApplicationDocumentsDirectory()).path;
|
||||||
|
final String filename = p.join(dir, ".pili_logs");
|
||||||
|
final file = File(filename);
|
||||||
|
if (!await file.exists()) {
|
||||||
|
await file.create();
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> clearLogs() async {
|
||||||
|
String dir = (await getApplicationDocumentsDirectory()).path;
|
||||||
|
final String filename = p.join(dir, ".pili_logs");
|
||||||
|
final file = File(filename);
|
||||||
|
try {
|
||||||
|
await file.writeAsString('');
|
||||||
|
} catch (e) {
|
||||||
|
print('Error clearing file: $e');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -1,51 +1,65 @@
|
|||||||
// ignore_for_file: constant_identifier_names
|
// ignore_for_file: constant_identifier_names, non_constant_identifier_names
|
||||||
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:math';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class IdUtils {
|
class IdUtils {
|
||||||
static const String TABLE =
|
static final XOR_CODE = BigInt.parse('23442827791579');
|
||||||
'fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF';
|
static final MASK_CODE = BigInt.parse('2251799813685247');
|
||||||
static const List<int> S = [11, 10, 3, 8, 4, 6]; // 位置编码表
|
static final MAX_AID = BigInt.one << (BigInt.from(51)).toInt();
|
||||||
static const int XOR = 177451812; // 固定异或值
|
static final BASE = BigInt.from(58);
|
||||||
static const int ADD = 8728348608; // 固定加法值
|
|
||||||
static const List<String> r = [
|
static const data =
|
||||||
'B',
|
'FcwAPNKTMug3GV5Lj7EJnHpWsx4tb8haYeviqBz6rkCy12mUSDQX9RdoZf';
|
||||||
'V',
|
|
||||||
'1',
|
|
||||||
'',
|
|
||||||
'',
|
|
||||||
'4',
|
|
||||||
'',
|
|
||||||
'1',
|
|
||||||
'',
|
|
||||||
'7',
|
|
||||||
'',
|
|
||||||
''
|
|
||||||
];
|
|
||||||
|
|
||||||
/// av转bv
|
/// av转bv
|
||||||
static String av2bv(int av) {
|
static String av2bv(int aid) {
|
||||||
int x_ = (av ^ XOR) + ADD;
|
List<String> bytes = [
|
||||||
List<String> newR = [];
|
'B',
|
||||||
newR.addAll(r);
|
'V',
|
||||||
for (int i = 0; i < S.length; i++) {
|
'1',
|
||||||
newR[S[i]] =
|
'0',
|
||||||
TABLE.characters.elementAt((x_ / pow(58, i).toInt() % 58).toInt());
|
'0',
|
||||||
|
'0',
|
||||||
|
'0',
|
||||||
|
'0',
|
||||||
|
'0',
|
||||||
|
'0',
|
||||||
|
'0',
|
||||||
|
'0'
|
||||||
|
];
|
||||||
|
int bvIndex = bytes.length - 1;
|
||||||
|
BigInt tmp = (MAX_AID | BigInt.from(aid)) ^ XOR_CODE;
|
||||||
|
while (tmp > BigInt.zero) {
|
||||||
|
bytes[bvIndex] = data[(tmp % BASE).toInt()];
|
||||||
|
tmp = tmp ~/ BASE;
|
||||||
|
bvIndex -= 1;
|
||||||
}
|
}
|
||||||
return newR.join();
|
String tmpSwap = bytes[3];
|
||||||
|
bytes[3] = bytes[9];
|
||||||
|
bytes[9] = tmpSwap;
|
||||||
|
|
||||||
|
tmpSwap = bytes[4];
|
||||||
|
bytes[4] = bytes[7];
|
||||||
|
bytes[7] = tmpSwap;
|
||||||
|
|
||||||
|
return bytes.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// bv转bv
|
/// bv转av
|
||||||
static int bv2av(String bv) {
|
static int bv2av(String bvid) {
|
||||||
int r = 0;
|
List<String> bvidArr = bvid.split('');
|
||||||
for (int i = 0; i < S.length; i++) {
|
final tmpValue = bvidArr[3];
|
||||||
r += (TABLE.indexOf(bv.characters.elementAt(S[i])).toInt()) *
|
bvidArr[3] = bvidArr[9];
|
||||||
pow(58, i).toInt();
|
bvidArr[9] = tmpValue;
|
||||||
}
|
|
||||||
return (r - ADD) ^ XOR;
|
final tmpValue2 = bvidArr[4];
|
||||||
|
bvidArr[4] = bvidArr[7];
|
||||||
|
bvidArr[7] = tmpValue2;
|
||||||
|
|
||||||
|
bvidArr.removeRange(0, 3);
|
||||||
|
BigInt tmp = bvidArr.fold(BigInt.zero,
|
||||||
|
(pre, bvidChar) => pre * BASE + BigInt.from(data.indexOf(bvidChar)));
|
||||||
|
return ((tmp & MASK_CODE) ^ XOR_CODE).toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 匹配
|
// 匹配
|
||||||
|
|||||||
52
pubspec.lock
52
pubspec.lock
@@ -208,7 +208,15 @@ packages:
|
|||||||
sha256: "42a835caa27c220d1294311ac409a43361088625a4f23c820b006dd9bffb3316"
|
sha256: "42a835caa27c220d1294311ac409a43361088625a4f23c820b006dd9bffb3316"
|
||||||
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
|
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.1.0"
|
||||||
|
catcher_2:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: catcher_2
|
||||||
|
sha256: ca94d45ffb52bf4b16a425cdff6734ae8443d36d5f06c276f1c2a593120b11ed
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -547,6 +555,14 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_mailer:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_mailer
|
||||||
|
sha256: "4fffaa35e911ff5ec2e5a4ebbca62c372e99a154eb3bb2c0bf79f09adf6ecf4c"
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
flutter_plugin_android_lifecycle:
|
flutter_plugin_android_lifecycle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -589,6 +605,14 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
fluttertoast:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: fluttertoast
|
||||||
|
sha256: dfdde255317af381bfc1c486ed968d5a43a2ded9c931e87cbecd88767d6a71c1
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "8.2.4"
|
||||||
font_awesome_flutter:
|
font_awesome_flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -781,6 +805,14 @@ packages:
|
|||||||
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
|
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "3.0.0"
|
||||||
|
logger:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: logger
|
||||||
|
sha256: "6bbb9d6f7056729537a4309bda2e74e18e5d9f14302489cc1e93f33b3fe32cac"
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.2+1"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -789,6 +821,14 @@ packages:
|
|||||||
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
|
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.2.0"
|
||||||
|
mailer:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: mailer
|
||||||
|
sha256: "57f6dd1496699999a7bfd0aa6be0645384f477f4823e16d4321c40a434346382"
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "6.0.1"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -951,7 +991,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.0.1"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: path
|
name: path
|
||||||
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
|
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
|
||||||
@@ -1214,6 +1254,14 @@ packages:
|
|||||||
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
|
url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.8"
|
version: "0.3.8"
|
||||||
|
sentry:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sentry
|
||||||
|
sha256: "5686ed515bb620dc52b4ae99a6586fe720d443591183cf1f620ec5d1f0eec100"
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "7.15.0"
|
||||||
share_plus:
|
share_plus:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|||||||
11
pubspec.yaml
11
pubspec.yaml
@@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 1.0.17+1017
|
version: 1.0.19+1019
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.19.6 <3.0.0"
|
sdk: ">=2.19.6 <3.0.0"
|
||||||
@@ -85,8 +85,8 @@ dependencies:
|
|||||||
encrypt: ^5.0.3
|
encrypt: ^5.0.3
|
||||||
|
|
||||||
# 视频播放器
|
# 视频播放器
|
||||||
media_kit: ^1.1.10 # Primary package.
|
media_kit: ^1.1.10 # Primary package.
|
||||||
media_kit_video: ^1.2.4 # For video rendering.
|
media_kit_video: ^1.2.4 # For video rendering.
|
||||||
media_kit_libs_video: ^1.0.4
|
media_kit_libs_video: ^1.0.4
|
||||||
|
|
||||||
# 媒体通知
|
# 媒体通知
|
||||||
@@ -134,7 +134,9 @@ dependencies:
|
|||||||
uuid: ^3.0.7
|
uuid: ^3.0.7
|
||||||
scrollable_positioned_list: ^0.3.8
|
scrollable_positioned_list: ^0.3.8
|
||||||
nil: ^1.1.1
|
nil: ^1.1.1
|
||||||
|
catcher_2: ^1.1.0
|
||||||
|
logger: ^2.0.2+1
|
||||||
|
path: 1.8.3
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@@ -205,6 +207,5 @@ flutter:
|
|||||||
# fonts:
|
# fonts:
|
||||||
# - asset: assets/fonts/HarmonyOS_Sans_SC_Regular.ttf
|
# - asset: assets/fonts/HarmonyOS_Sans_SC_Regular.ttf
|
||||||
|
|
||||||
|
|
||||||
# For details regarding fonts from package dependencies,
|
# For details regarding fonts from package dependencies,
|
||||||
# see https://flutter.dev/custom-fonts/#from-packages
|
# see https://flutter.dev/custom-fonts/#from-packages
|
||||||
|
|||||||
Reference in New Issue
Block a user