Compare commits
29 Commits
v1.0.14.12
...
feature-bu
| Author | SHA1 | Date | |
|---|---|---|---|
| 2ece96df21 | |||
| c11c5695a2 | |||
| 93581c2932 | |||
| fd43a8cb31 | |||
| 6f34bacb64 | |||
| 90314f89ed | |||
| 45c53de2c2 | |||
| 5c07cb4545 | |||
| 844053b138 | |||
| 6af8b91f63 | |||
| 8aa02f7450 | |||
| 38a1f2e1f7 | |||
| b2e1d98f51 | |||
| e19cf92992 | |||
| 80e10aeaad | |||
| b1a9152a49 | |||
| 935b7577b3 | |||
| fd5c4463d2 | |||
| 7fcbe4dd9d | |||
| 9a0c9f4021 | |||
| 6b3773a074 | |||
| 7be8ebaa7e | |||
| 092b1cee3d | |||
| 252f39e8c7 | |||
| e631ca04a0 | |||
| 3665d6a0f6 | |||
| e3c9e8c13b | |||
| 39995bae23 | |||
| f42d0d01ea |
2
.github/workflows/main.yml
vendored
@ -36,7 +36,7 @@ jobs:
|
|||||||
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.4
|
flutter-version: 3.10.6
|
||||||
channel: any
|
channel: any
|
||||||
|
|
||||||
- name: 下载项目依赖
|
- name: 下载项目依赖
|
||||||
|
|||||||
@ -3,17 +3,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<h1>PiliPala</h1>
|
<h1>PiliPala</h1>
|
||||||
<div align="center">
|
|
||||||
|
|
||||||

|
|
||||||

|
|
||||||

|
|
||||||
</div>
|
|
||||||
<p>使用Flutter开发的BiliBili第三方客户端</p>
|
<p>使用Flutter开发的BiliBili第三方客户端</p>
|
||||||
|
<br/>
|
||||||
<img src="https://github.com/guozhigq/pilipala/blob/main/assets/sreenshot/510shots_so.png" width="32%" alt="home" />
|
<img src="https://github.com/guozhigq/pilipala/blob/main/assets/sreenshot/510shots_so.png" width="32%" alt="home" />
|
||||||
<img src="https://github.com/guozhigq/pilipala/blob/main/assets/sreenshot/174shots_so.png" width="32%" alt="home" />
|
<img src="https://github.com/guozhigq/pilipala/blob/main/assets/sreenshot/174shots_so.png" width="32%" alt="home" />
|
||||||
<img src="https://github.com/guozhigq/pilipala/blob/main/assets/sreenshot/850shots_so.png" width="32%" alt="home" />
|
<img src="https://github.com/guozhigq/pilipala/blob/main/assets/sreenshot/850shots_so.png" width="32%" alt="home" />
|
||||||
|
|||||||
@ -63,7 +63,6 @@ android {
|
|||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
minSdkVersion 19
|
minSdkVersion 19
|
||||||
multiDexEnabled true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
|
|||||||
@ -39,13 +39,9 @@
|
|||||||
android:label="PiliPala"
|
android:label="PiliPala"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
android:enableOnBackInvokedCallback="true">
|
||||||
android:enableOnBackInvokedCallback="true"
|
|
||||||
android:allowBackup="false"
|
|
||||||
android:fullBackupContent="false"
|
|
||||||
tools:replace="android:allowBackup">
|
|
||||||
<activity
|
<activity
|
||||||
android:name="com.ryanheise.audioservice.AudioServiceActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
@ -226,24 +222,6 @@
|
|||||||
|
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<service
|
|
||||||
android:name="com.ryanheise.audioservice.AudioService"
|
|
||||||
android:foregroundServiceType="mediaPlayback"
|
|
||||||
android:exported="true"
|
|
||||||
tools:ignore="Instantiatable">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.media.browse.MediaBrowserService" />
|
|
||||||
</intent-filter>
|
|
||||||
</service>
|
|
||||||
|
|
||||||
<receiver
|
|
||||||
android:name="com.ryanheise.audioservice.MediaButtonReceiver"
|
|
||||||
android:exported="true"
|
|
||||||
tools:ignore="Instantiatable">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MEDIA_BUTTON" />
|
|
||||||
</intent-filter>
|
|
||||||
</receiver>
|
|
||||||
<!-- Don't delete the meta-data below.
|
<!-- Don't delete the meta-data below.
|
||||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||||
<meta-data
|
<meta-data
|
||||||
@ -256,8 +234,6 @@
|
|||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
|
||||||
<!--
|
<!--
|
||||||
Media access permissions.
|
Media access permissions.
|
||||||
Android 13 or higher.
|
Android 13 or higher.
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 528 B |
|
Before Width: | Height: | Size: 337 B |
|
Before Width: | Height: | Size: 648 B |
|
Before Width: | Height: | Size: 962 B |
|
Before Width: | Height: | Size: 1.2 KiB |
@ -1,7 +0,0 @@
|
|||||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
|
||||||
android:viewportHeight="24" android:viewportWidth="24"
|
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M18,13c0,3.31 -2.69,6 -6,6s-6,-2.69 -6,-6s2.69,-6 6,-6v4l5,-5l-5,-5v4c-4.42,0 -8,3.58 -8,8c0,4.42 3.58,8 8,8s8,-3.58 8,-8H18z"/>
|
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M10.86,15.94l0,-4.27l-0.09,0l-1.77,0.63l0,0.69l1.01,-0.31l0,3.26z"/>
|
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M12.25,13.44v0.74c0,1.9 1.31,1.82 1.44,1.82c0.14,0 1.44,0.09 1.44,-1.82v-0.74c0,-1.9 -1.31,-1.82 -1.44,-1.82C13.55,11.62 12.25,11.53 12.25,13.44zM14.29,13.32v0.97c0,0.77 -0.21,1.03 -0.59,1.03c-0.38,0 -0.6,-0.26 -0.6,-1.03v-0.97c0,-0.75 0.22,-1.01 0.59,-1.01C14.07,12.3 14.29,12.57 14.29,13.32z"/>
|
|
||||||
</vector>
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
<vector android:height="24dp" android:tint="#FFFFFF"
|
|
||||||
android:viewportHeight="24" android:viewportWidth="24"
|
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M11.99,5V1l-5,5l5,5V7c3.31,0 6,2.69 6,6s-2.69,6 -6,6s-6,-2.69 -6,-6h-2c0,4.42 3.58,8 8,8s8,-3.58 8,-8S16.41,5 11.99,5z"/>
|
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M10.89,16h-0.85v-3.26l-1.01,0.31v-0.69l1.77,-0.63h0.09V16z"/>
|
|
||||||
<path android:fillColor="@android:color/white" android:pathData="M15.17,14.24c0,0.32 -0.03,0.6 -0.1,0.82s-0.17,0.42 -0.29,0.57s-0.28,0.26 -0.45,0.33s-0.37,0.1 -0.59,0.1s-0.41,-0.03 -0.59,-0.1s-0.33,-0.18 -0.46,-0.33s-0.23,-0.34 -0.3,-0.57s-0.11,-0.5 -0.11,-0.82V13.5c0,-0.32 0.03,-0.6 0.1,-0.82s0.17,-0.42 0.29,-0.57s0.28,-0.26 0.45,-0.33s0.37,-0.1 0.59,-0.1s0.41,0.03 0.59,0.1c0.18,0.07 0.33,0.18 0.46,0.33s0.23,0.34 0.3,0.57s0.11,0.5 0.11,0.82V14.24zM14.32,13.38c0,-0.19 -0.01,-0.35 -0.04,-0.48s-0.07,-0.23 -0.12,-0.31s-0.11,-0.14 -0.19,-0.17s-0.16,-0.05 -0.25,-0.05s-0.18,0.02 -0.25,0.05s-0.14,0.09 -0.19,0.17s-0.09,0.18 -0.12,0.31s-0.04,0.29 -0.04,0.48v0.97c0,0.19 0.01,0.35 0.04,0.48s0.07,0.24 0.12,0.32s0.11,0.14 0.19,0.17s0.16,0.05 0.25,0.05s0.18,-0.02 0.25,-0.05s0.14,-0.09 0.19,-0.17s0.09,-0.19 0.11,-0.32s0.04,-0.29 0.04,-0.48V13.38z"/>
|
|
||||||
</vector>
|
|
||||||
@ -2,5 +2,4 @@
|
|||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<background android:drawable="@color/ic_launcher_background"/>
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||||
<monochrome android:drawable="@drawable/ic_launcher_foreground"/>
|
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
||||||
|
|||||||
@ -1,3 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
tools:keep="@drawable/*" />
|
|
||||||
|
Before Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 186 B |
@ -1,4 +0,0 @@
|
|||||||
## 1.0.10
|
|
||||||
|
|
||||||
### 修复
|
|
||||||
+ 长按倍速抬起后未恢复默认倍速
|
|
||||||
@ -1,26 +0,0 @@
|
|||||||
## 1.0.11
|
|
||||||
|
|
||||||
### 新功能
|
|
||||||
+ 适配了原生媒体通知栏 @Daydreamer-riri
|
|
||||||
+ 视频主题图标 @Daydreamer-riri
|
|
||||||
+ 关闭软件后自动画中画播放
|
|
||||||
+ UP主分组管理
|
|
||||||
+ md2样式底栏
|
|
||||||
+
|
|
||||||
|
|
||||||
|
|
||||||
### 修复
|
|
||||||
+ 历史记录记忆播放
|
|
||||||
+ 部分类型视频连播
|
|
||||||
+ 播放速度选择框不支持返回手势
|
|
||||||
+ 播放速度选择框不支持返回手势
|
|
||||||
+ 视频播放速度总是显示1.0X
|
|
||||||
+ 评论页面计数错误
|
|
||||||
+ 退出视频还有声音
|
|
||||||
|
|
||||||
|
|
||||||
### 优化
|
|
||||||
+ 视频加载速度
|
|
||||||
|
|
||||||
更多更新日志可在Github上查看
|
|
||||||
问题反馈、功能建议请查看「关于」页面。
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
## 1.0.12
|
|
||||||
|
|
||||||
|
|
||||||
### 修复
|
|
||||||
+ iOS端视频播放时没有声音
|
|
||||||
+ 超过6分钟弹幕不显示
|
|
||||||
+ 视频详情页网络异常
|
|
||||||
|
|
||||||
|
|
||||||
更多更新日志可在Github上查看
|
|
||||||
问题反馈、功能建议请查看「关于」页面。
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
## 1.0.13
|
|
||||||
|
|
||||||
|
|
||||||
### 新功能
|
|
||||||
+ 视频详情页稍后再看
|
|
||||||
+ 发送弹幕 感谢@orz12
|
|
||||||
+ 消息展示
|
|
||||||
+ up主页显示获赞数
|
|
||||||
+ up主页显示合集
|
|
||||||
+ 视频详情页「ai总结」增加开关
|
|
||||||
|
|
||||||
### 修复
|
|
||||||
+ 首页推荐问题(需要重新登录)
|
|
||||||
+ 长按倍速逻辑
|
|
||||||
+ 视频详情页网络异常
|
|
||||||
|
|
||||||
### 优化
|
|
||||||
+ 设置面板样式 感谢@GuMengYu @KoolShow
|
|
||||||
|
|
||||||
|
|
||||||
更多更新日志可在Github上查看
|
|
||||||
问题反馈、功能建议请查看「关于」页面。
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
## 1.0.14
|
|
||||||
|
|
||||||
圣诞节快乐~ 🎉
|
|
||||||
|
|
||||||
大部分内容由@orz12提供,感谢👏
|
|
||||||
|
|
||||||
### 修复
|
|
||||||
+ 全屏弹幕消失
|
|
||||||
+ iOS全屏/退出全屏视频暂停
|
|
||||||
+ 个人主页关注状态
|
|
||||||
+ 视频合集向下滑动UI问题
|
|
||||||
+ 媒体库滑动底栏不隐藏
|
|
||||||
+ 个人主页动态加载问题 * 2
|
|
||||||
+ 未登录状态访问个人主页异常
|
|
||||||
+ 视频搜索标题特殊字符转义
|
|
||||||
+ iOS闪退
|
|
||||||
+ 消息页面夜间模式异常
|
|
||||||
+ 消息页面含有撤回消息时异常
|
|
||||||
+ 弹幕速度
|
|
||||||
|
|
||||||
### 优化
|
|
||||||
+ 全屏播放方案优化
|
|
||||||
+ 弹幕加载逻辑优化
|
|
||||||
+ 点赞、投币逻辑优化
|
|
||||||
+ 进度条及播放时间渲染优化
|
|
||||||
|
|
||||||
更多更新日志可在Github上查看
|
|
||||||
问题反馈、功能建议请查看「关于」页面。
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
## 1.0.8
|
|
||||||
|
|
||||||
直播弹幕、循环播放等功能开发中
|
|
||||||
|
|
||||||
### 新功能
|
|
||||||
+ 用户拉黑功能
|
|
||||||
+ gif图片保存
|
|
||||||
+ 删除已看历史记录
|
|
||||||
|
|
||||||
### 修复
|
|
||||||
+ 弹幕数量较少
|
|
||||||
+ 弹幕屏蔽设置自动记忆
|
|
||||||
+ 动态页面渲染
|
|
||||||
+ 用户主页数据错乱
|
|
||||||
+ 大家都在搜空白
|
|
||||||
+ 默认自动全屏,顶部操作栏丢失
|
|
||||||
|
|
||||||
|
|
||||||
### 优化
|
|
||||||
+ 全屏状态栏区域显示优化
|
|
||||||
+ 图片保存至PiliPala文件夹
|
|
||||||
|
|
||||||
更多更新日志可在Github上查看
|
|
||||||
问题反馈、功能建议请查看「关于」页面。
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
## 1.0.9
|
|
||||||
|
|
||||||
|
|
||||||
### 新功能
|
|
||||||
+ 自定义倍速、默认倍速
|
|
||||||
+ 历史记录搜索
|
|
||||||
+ 收藏夹搜索
|
|
||||||
+ 历史记录多选删除
|
|
||||||
+ 视频循环播放
|
|
||||||
+ 免登录看1080P
|
|
||||||
+ 评论区视频链接跳转
|
|
||||||
+ up主分组
|
|
||||||
+ up主投稿搜索
|
|
||||||
|
|
||||||
### 修复
|
|
||||||
+ 搜索视频标题乱码
|
|
||||||
+ 屏幕帧率
|
|
||||||
+ 动态页面渲染
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 优化
|
|
||||||
+ 快进手势
|
|
||||||
+ 视频简介链接匹配
|
|
||||||
+ 视频全屏时安全区域
|
|
||||||
|
|
||||||
更多更新日志可在Github上查看
|
|
||||||
问题反馈、功能建议请查看「关于」页面。
|
|
||||||
@ -37,11 +37,5 @@ end
|
|||||||
post_install do |installer|
|
post_install do |installer|
|
||||||
installer.pods_project.targets.each do |target|
|
installer.pods_project.targets.each do |target|
|
||||||
flutter_additional_ios_build_settings(target)
|
flutter_additional_ios_build_settings(target)
|
||||||
target.build_configurations.each do |config|
|
|
||||||
deployment_target = config.build_settings['IPHONEOS_DEPLOYMENT_TARGET']
|
|
||||||
if !deployment_target.nil? && !deployment_target.empty? && deployment_target.to_f < 12.0
|
|
||||||
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1,12 +1,6 @@
|
|||||||
PODS:
|
PODS:
|
||||||
- appscheme (1.0.4):
|
- appscheme (1.0.4):
|
||||||
- Flutter
|
- Flutter
|
||||||
- audio_service (0.0.1):
|
|
||||||
- Flutter
|
|
||||||
- audio_session (0.0.1):
|
|
||||||
- Flutter
|
|
||||||
- auto_orientation (0.0.1):
|
|
||||||
- Flutter
|
|
||||||
- connectivity_plus (0.0.1):
|
- connectivity_plus (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- ReachabilitySwift
|
- ReachabilitySwift
|
||||||
@ -18,10 +12,8 @@ PODS:
|
|||||||
- 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)
|
||||||
- gt3_flutter_plugin (0.0.8):
|
- image_gallery_saver (2.0.2):
|
||||||
- Flutter
|
- Flutter
|
||||||
- GT3Captcha-iOS
|
|
||||||
- GT3Captcha-iOS (0.15.8.3)
|
|
||||||
- media_kit_libs_ios_video (1.0.4):
|
- media_kit_libs_ios_video (1.0.4):
|
||||||
- Flutter
|
- Flutter
|
||||||
- media_kit_native_event_loop (1.0.0):
|
- media_kit_native_event_loop (1.0.0):
|
||||||
@ -36,8 +28,6 @@ PODS:
|
|||||||
- permission_handler_apple (9.1.1):
|
- permission_handler_apple (9.1.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- ReachabilitySwift (5.0.0)
|
- ReachabilitySwift (5.0.0)
|
||||||
- saver_gallery (0.0.1):
|
|
||||||
- Flutter
|
|
||||||
- screen_brightness_ios (0.1.0):
|
- screen_brightness_ios (0.1.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
- share_plus (0.0.1):
|
- share_plus (0.0.1):
|
||||||
@ -62,21 +52,17 @@ PODS:
|
|||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- appscheme (from `.symlinks/plugins/appscheme/ios`)
|
- appscheme (from `.symlinks/plugins/appscheme/ios`)
|
||||||
- audio_service (from `.symlinks/plugins/audio_service/ios`)
|
|
||||||
- audio_session (from `.symlinks/plugins/audio_session/ios`)
|
|
||||||
- auto_orientation (from `.symlinks/plugins/auto_orientation/ios`)
|
|
||||||
- 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_volume_controller (from `.symlinks/plugins/flutter_volume_controller/ios`)
|
- flutter_volume_controller (from `.symlinks/plugins/flutter_volume_controller/ios`)
|
||||||
- gt3_flutter_plugin (from `.symlinks/plugins/gt3_flutter_plugin/ios`)
|
- image_gallery_saver (from `.symlinks/plugins/image_gallery_saver/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`)
|
||||||
- media_kit_video (from `.symlinks/plugins/media_kit_video/ios`)
|
- media_kit_video (from `.symlinks/plugins/media_kit_video/ios`)
|
||||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||||
- saver_gallery (from `.symlinks/plugins/saver_gallery/ios`)
|
|
||||||
- screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`)
|
- screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`)
|
||||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||||
- sqflite (from `.symlinks/plugins/sqflite/ios`)
|
- sqflite (from `.symlinks/plugins/sqflite/ios`)
|
||||||
@ -91,18 +77,11 @@ DEPENDENCIES:
|
|||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
trunk:
|
trunk:
|
||||||
- FMDB
|
- FMDB
|
||||||
- GT3Captcha-iOS
|
|
||||||
- ReachabilitySwift
|
- ReachabilitySwift
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
appscheme:
|
appscheme:
|
||||||
:path: ".symlinks/plugins/appscheme/ios"
|
:path: ".symlinks/plugins/appscheme/ios"
|
||||||
audio_service:
|
|
||||||
:path: ".symlinks/plugins/audio_service/ios"
|
|
||||||
audio_session:
|
|
||||||
:path: ".symlinks/plugins/audio_session/ios"
|
|
||||||
auto_orientation:
|
|
||||||
:path: ".symlinks/plugins/auto_orientation/ios"
|
|
||||||
connectivity_plus:
|
connectivity_plus:
|
||||||
:path: ".symlinks/plugins/connectivity_plus/ios"
|
:path: ".symlinks/plugins/connectivity_plus/ios"
|
||||||
device_info_plus:
|
device_info_plus:
|
||||||
@ -111,8 +90,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: Flutter
|
:path: Flutter
|
||||||
flutter_volume_controller:
|
flutter_volume_controller:
|
||||||
:path: ".symlinks/plugins/flutter_volume_controller/ios"
|
:path: ".symlinks/plugins/flutter_volume_controller/ios"
|
||||||
gt3_flutter_plugin:
|
image_gallery_saver:
|
||||||
:path: ".symlinks/plugins/gt3_flutter_plugin/ios"
|
:path: ".symlinks/plugins/image_gallery_saver/ios"
|
||||||
media_kit_libs_ios_video:
|
media_kit_libs_ios_video:
|
||||||
:path: ".symlinks/plugins/media_kit_libs_ios_video/ios"
|
:path: ".symlinks/plugins/media_kit_libs_ios_video/ios"
|
||||||
media_kit_native_event_loop:
|
media_kit_native_event_loop:
|
||||||
@ -125,8 +104,6 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||||
permission_handler_apple:
|
permission_handler_apple:
|
||||||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||||
saver_gallery:
|
|
||||||
:path: ".symlinks/plugins/saver_gallery/ios"
|
|
||||||
screen_brightness_ios:
|
screen_brightness_ios:
|
||||||
:path: ".symlinks/plugins/screen_brightness_ios/ios"
|
:path: ".symlinks/plugins/screen_brightness_ios/ios"
|
||||||
share_plus:
|
share_plus:
|
||||||
@ -150,35 +127,30 @@ EXTERNAL SOURCES:
|
|||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
appscheme: b1c3f8862331cb20430cf9e0e4af85dbc1572ad8
|
appscheme: b1c3f8862331cb20430cf9e0e4af85dbc1572ad8
|
||||||
audio_service: f509d65da41b9521a61f1c404dd58651f265a567
|
|
||||||
audio_session: 4f3e461722055d21515cf3261b64c973c062f345
|
|
||||||
auto_orientation: 102ed811a5938d52c86520ddd7ecd3a126b5d39d
|
|
||||||
connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a
|
connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a
|
||||||
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
|
device_info_plus: 7545d84d8d1b896cb16a4ff98c19f07ec4b298ea
|
||||||
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
||||||
flutter_volume_controller: e4d5832f08008180f76e30faf671ffd5a425e529
|
flutter_volume_controller: e4d5832f08008180f76e30faf671ffd5a425e529
|
||||||
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
||||||
gt3_flutter_plugin: bfa1f26e9a09dc00401514be5ed437f964cabf23
|
image_gallery_saver: cb43cc43141711190510e92c460eb1655cd343cb
|
||||||
GT3Captcha-iOS: 5e3b1077834d8a9d6f4d64a447a30af3e14affe6
|
|
||||||
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
|
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
|
||||||
media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a
|
media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a
|
||||||
media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
|
media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
|
||||||
package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
|
package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7
|
||||||
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
|
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
|
||||||
permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
|
permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
|
||||||
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
|
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
|
||||||
saver_gallery: 2b4e584106fde2407ab51560f3851564963e6b78
|
|
||||||
screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625
|
screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625
|
||||||
share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5
|
share_plus: 599aa54e4ea31d4b4c0e9c911bcc26c55e791028
|
||||||
sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
|
sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
|
||||||
status_bar_control: 7c84146799e6a076315cc1550f78ef53aae3e446
|
status_bar_control: 7c84146799e6a076315cc1550f78ef53aae3e446
|
||||||
system_proxy: bec1a5c5af67dd3e3ebf43979400a8756c04cc44
|
system_proxy: bec1a5c5af67dd3e3ebf43979400a8756c04cc44
|
||||||
url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b
|
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
|
||||||
volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9
|
volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9
|
||||||
wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47
|
wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47
|
||||||
webview_cookie_manager: eaf920722b493bd0f7611b5484771ca53fed03f7
|
webview_cookie_manager: eaf920722b493bd0f7611b5484771ca53fed03f7
|
||||||
webview_flutter_wkwebview: 2e2d318f21a5e036e2c3f26171342e95908bd60a
|
webview_flutter_wkwebview: 2e2d318f21a5e036e2c3f26171342e95908bd60a
|
||||||
|
|
||||||
PODFILE CHECKSUM: 637cd290bed23275b5f5ffcc7eb1e73d0a5fb2be
|
PODFILE CHECKSUM: cc1f88378b4bfcf93a6ce00d2c587857c6008d3b
|
||||||
|
|
||||||
COCOAPODS: 1.14.3
|
COCOAPODS: 1.12.1
|
||||||
|
|||||||
@ -121,6 +121,7 @@
|
|||||||
3DA6FBBC55FDD1E3261D6D67 /* Pods-Runner.release.xcconfig */,
|
3DA6FBBC55FDD1E3261D6D67 /* Pods-Runner.release.xcconfig */,
|
||||||
32E2926120A1A8DC0E629BC6 /* Pods-Runner.profile.xcconfig */,
|
32E2926120A1A8DC0E629BC6 /* Pods-Runner.profile.xcconfig */,
|
||||||
);
|
);
|
||||||
|
name = Pods;
|
||||||
path = Pods;
|
path = Pods;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@ -139,7 +140,6 @@
|
|||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
5A372F23F3CF0118D6526BAC /* [CP] Embed Pods Frameworks */,
|
5A372F23F3CF0118D6526BAC /* [CP] Embed Pods Frameworks */,
|
||||||
B78851E7B29A4C3961AC483C /* [CP] Copy Pods Resources */,
|
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@ -156,7 +156,7 @@
|
|||||||
97C146E61CF9000F007C117D /* Project object */ = {
|
97C146E61CF9000F007C117D /* Project object */ = {
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastUpgradeCheck = 1430;
|
LastUpgradeCheck = 1300;
|
||||||
ORGANIZATIONNAME = "";
|
ORGANIZATIONNAME = "";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
97C146ED1CF9000F007C117D = {
|
97C146ED1CF9000F007C117D = {
|
||||||
@ -268,23 +268,6 @@
|
|||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||||
};
|
};
|
||||||
B78851E7B29A4C3961AC483C /* [CP] Copy Pods Resources */ = {
|
|
||||||
isa = PBXShellScriptBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
);
|
|
||||||
inputFileListPaths = (
|
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
|
||||||
);
|
|
||||||
name = "[CP] Copy Pods Resources";
|
|
||||||
outputFileListPaths = (
|
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
shellPath = /bin/sh;
|
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
|
||||||
showEnvVarsInLog = 0;
|
|
||||||
};
|
|
||||||
/* End PBXShellScriptBuildPhase section */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
@ -360,7 +343,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
@ -376,7 +359,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = RN352BA826;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
@ -438,7 +421,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = YES;
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
@ -487,7 +470,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SUPPORTED_PLATFORMS = iphoneos;
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
@ -505,7 +488,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = RN352BA826;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
@ -528,7 +511,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = RN352BA826;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1430"
|
LastUpgradeVersion = "1300"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
|
||||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22504"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
||||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<scenes>
|
<scenes>
|
||||||
<!--Flutter View Controller-->
|
<!--Flutter View Controller-->
|
||||||
@ -16,14 +14,13 @@
|
|||||||
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||||
</layoutGuides>
|
</layoutGuides>
|
||||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||||
</view>
|
</view>
|
||||||
</viewController>
|
</viewController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="-11" y="-41"/>
|
|
||||||
</scene>
|
</scene>
|
||||||
</scenes>
|
</scenes>
|
||||||
</document>
|
</document>
|
||||||
|
|||||||
@ -103,9 +103,5 @@
|
|||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
<key>UIBackgroundModes</key>
|
|
||||||
<array>
|
|
||||||
<string>audio</string>
|
|
||||||
</array>
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@ -9,11 +9,7 @@ class StyleString {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Constants {
|
class Constants {
|
||||||
// 27eb53fc9058f8c3 移动端 Android
|
static const String appKey = '27eb53fc9058f8c3';
|
||||||
// 4409e2ce8ffd12b8 TV端
|
|
||||||
static const String appKey = '4409e2ce8ffd12b8';
|
|
||||||
// 59b43e04ad6965f34319062b478f83dd TV端
|
|
||||||
static const String appSec = '59b43e04ad6965f34319062b478f83dd';
|
|
||||||
static const String thirdSign = '04224646d1fea004e79606d3b038c84a';
|
static const String thirdSign = '04224646d1fea004e79606d3b038c84a';
|
||||||
static const String thirdApi =
|
static const String thirdApi =
|
||||||
'https://www.mcbbs.net/template/mcbbs/image/special_photo_bg.png';
|
'https://www.mcbbs.net/template/mcbbs/image/special_photo_bg.png';
|
||||||
|
|||||||
@ -1,5 +1,37 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
// Widget pBadge(
|
||||||
|
// text,
|
||||||
|
// context,
|
||||||
|
// double? top,
|
||||||
|
// double? right,
|
||||||
|
// double? bottom,
|
||||||
|
// double? left, {
|
||||||
|
// type = 'primary',
|
||||||
|
// }) {
|
||||||
|
// Color bgColor = Theme.of(context).colorScheme.primary;
|
||||||
|
// Color color = Theme.of(context).colorScheme.onPrimary;
|
||||||
|
// if (type == 'gray') {
|
||||||
|
// bgColor = Colors.black54.withOpacity(0.4);
|
||||||
|
// color = Colors.white;
|
||||||
|
// }
|
||||||
|
// return Positioned(
|
||||||
|
// top: top,
|
||||||
|
// left: left,
|
||||||
|
// right: right,
|
||||||
|
// bottom: bottom,
|
||||||
|
// child: Container(
|
||||||
|
// padding: const EdgeInsets.symmetric(vertical: 1, horizontal: 6),
|
||||||
|
// decoration:
|
||||||
|
// BoxDecoration(borderRadius: BorderRadius.circular(4), color: bgColor),
|
||||||
|
// child: Text(
|
||||||
|
// text,
|
||||||
|
// style: TextStyle(fontSize: 11, color: color),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
class PBadge extends StatelessWidget {
|
class PBadge extends StatelessWidget {
|
||||||
final String? text;
|
final String? text;
|
||||||
final double? top;
|
final double? top;
|
||||||
|
|||||||
@ -1,47 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class ContentContainer extends StatelessWidget {
|
|
||||||
final Widget? contentWidget;
|
|
||||||
final Widget? bottomWidget;
|
|
||||||
final bool isScrollable;
|
|
||||||
final Clip? childClipBehavior;
|
|
||||||
|
|
||||||
const ContentContainer(
|
|
||||||
{Key? key,
|
|
||||||
this.contentWidget,
|
|
||||||
this.bottomWidget,
|
|
||||||
this.isScrollable = true,
|
|
||||||
this.childClipBehavior})
|
|
||||||
: super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return LayoutBuilder(
|
|
||||||
builder: (BuildContext context, BoxConstraints constraints) {
|
|
||||||
return SingleChildScrollView(
|
|
||||||
clipBehavior: childClipBehavior ?? Clip.hardEdge,
|
|
||||||
physics: isScrollable ? null : NeverScrollableScrollPhysics(),
|
|
||||||
child: ConstrainedBox(
|
|
||||||
constraints: constraints.copyWith(
|
|
||||||
minHeight: constraints.maxHeight,
|
|
||||||
maxHeight: double.infinity,
|
|
||||||
),
|
|
||||||
child: IntrinsicHeight(
|
|
||||||
child: Column(
|
|
||||||
children: <Widget>[
|
|
||||||
if (contentWidget != null)
|
|
||||||
Expanded(
|
|
||||||
child: contentWidget!,
|
|
||||||
)
|
|
||||||
else
|
|
||||||
Spacer(),
|
|
||||||
if (bottomWidget != null) bottomWidget!,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_html/flutter_html.dart';
|
import 'package:flutter_html/flutter_html.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
|
||||||
|
|
||||||
// ignore: must_be_immutable
|
// ignore: must_be_immutable
|
||||||
class HtmlRender extends StatelessWidget {
|
class HtmlRender extends StatelessWidget {
|
||||||
@ -20,47 +20,35 @@ class HtmlRender extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Html(
|
return Html(
|
||||||
data: htmlContent,
|
data: htmlContent,
|
||||||
|
// tagsList: Html.tags..addAll(["form", "label", "input"]),
|
||||||
onLinkTap: (url, buildContext, attributes) => {},
|
onLinkTap: (url, buildContext, attributes) => {},
|
||||||
extensions: [
|
extensions: [
|
||||||
TagExtension(
|
TagExtension(
|
||||||
tagsToExtend: {"img"},
|
tagsToExtend: {"img"},
|
||||||
builder: (extensionContext) {
|
builder: (extensionContext) {
|
||||||
try {
|
String? imgUrl = extensionContext.attributes['src'];
|
||||||
Map attributes = extensionContext.attributes;
|
|
||||||
List key = attributes.keys.toList();
|
|
||||||
String? imgUrl = key.contains('src')
|
|
||||||
? attributes['src']
|
|
||||||
: attributes['data-src'];
|
|
||||||
if (imgUrl!.startsWith('//')) {
|
if (imgUrl!.startsWith('//')) {
|
||||||
imgUrl = 'https:$imgUrl';
|
imgUrl = 'https:$imgUrl';
|
||||||
}
|
}
|
||||||
if (imgUrl.startsWith('http://')) {
|
if (imgUrl.startsWith('http://')) {
|
||||||
imgUrl = imgUrl.replaceAll('http://', 'https://');
|
imgUrl = imgUrl.replaceAll('http://', 'https://');
|
||||||
}
|
}
|
||||||
imgUrl = imgUrl.contains('@') ? imgUrl.split('@').first : imgUrl;
|
|
||||||
|
print(imgUrl);
|
||||||
bool isEmote = imgUrl.contains('/emote/');
|
bool isEmote = imgUrl.contains('/emote/');
|
||||||
bool isMall = imgUrl.contains('/mall/');
|
bool isMall = imgUrl.contains('/mall/');
|
||||||
if (isMall) {
|
if (isMall) {
|
||||||
return const SizedBox();
|
return SizedBox();
|
||||||
}
|
}
|
||||||
// bool inTable =
|
// bool inTable =
|
||||||
// extensionContext.element!.previousElementSibling == null ||
|
// extensionContext.element!.previousElementSibling == null ||
|
||||||
// extensionContext.element!.nextElementSibling == null;
|
// extensionContext.element!.nextElementSibling == null;
|
||||||
// imgUrl = Utils().imageUrl(imgUrl!);
|
// imgUrl = Utils().imageUrl(imgUrl!);
|
||||||
// return Image.network(
|
return Image.network(
|
||||||
// imgUrl,
|
imgUrl,
|
||||||
// width: isEmote ? 22 : null,
|
width: isEmote ? 22 : null,
|
||||||
// height: isEmote ? 22 : null,
|
height: isEmote ? 22 : null,
|
||||||
// );
|
|
||||||
return NetworkImgLayer(
|
|
||||||
width: isEmote ? 22 : Get.size.width - 24,
|
|
||||||
height: isEmote ? 22 : 200,
|
|
||||||
src: imgUrl,
|
|
||||||
);
|
);
|
||||||
} catch (err) {
|
|
||||||
print(err);
|
|
||||||
return const SizedBox();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -75,13 +63,11 @@ class HtmlRender extends StatelessWidget {
|
|||||||
textDecoration: TextDecoration.none,
|
textDecoration: TextDecoration.none,
|
||||||
),
|
),
|
||||||
"p": Style(
|
"p": Style(
|
||||||
margin: Margins.only(bottom: 10),
|
margin: Margins.only(bottom: 0),
|
||||||
),
|
),
|
||||||
"span": Style(
|
"span": Style(
|
||||||
fontSize: FontSize.medium,
|
fontSize: FontSize.medium,
|
||||||
height: Height(1.65),
|
|
||||||
),
|
),
|
||||||
"div": Style(height: Height.auto()),
|
|
||||||
"li > p": Style(
|
"li > p": Style(
|
||||||
display: Display.inline,
|
display: Display.inline,
|
||||||
),
|
),
|
||||||
@ -89,7 +75,61 @@ class HtmlRender extends StatelessWidget {
|
|||||||
padding: HtmlPaddings.only(bottom: 4),
|
padding: HtmlPaddings.only(bottom: 4),
|
||||||
textAlign: TextAlign.justify,
|
textAlign: TextAlign.justify,
|
||||||
),
|
),
|
||||||
"img": Style(margin: Margins.only(top: 4, bottom: 4)),
|
"image": Style(margin: Margins.only(top: 4, bottom: 4)),
|
||||||
|
"p > img": Style(margin: Margins.only(top: 4, bottom: 4)),
|
||||||
|
"code": Style(
|
||||||
|
backgroundColor: Theme.of(context).colorScheme.onInverseSurface),
|
||||||
|
"code > span": Style(textAlign: TextAlign.start),
|
||||||
|
"hr": Style(
|
||||||
|
margin: Margins.zero,
|
||||||
|
padding: HtmlPaddings.zero,
|
||||||
|
border: Border(
|
||||||
|
top: BorderSide(
|
||||||
|
width: 1.0,
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.onBackground.withOpacity(0.3),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'table': Style(
|
||||||
|
border: Border(
|
||||||
|
right: BorderSide(
|
||||||
|
width: 0.5,
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.onBackground.withOpacity(0.3),
|
||||||
|
),
|
||||||
|
bottom: BorderSide(
|
||||||
|
width: 0.5,
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.onBackground.withOpacity(0.3),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'tr': Style(
|
||||||
|
border: Border(
|
||||||
|
top: BorderSide(
|
||||||
|
width: 1.0,
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.onBackground.withOpacity(0.3),
|
||||||
|
),
|
||||||
|
left: BorderSide(
|
||||||
|
width: 1.0,
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.onBackground.withOpacity(0.3),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'thead': Style(
|
||||||
|
backgroundColor: Theme.of(context).colorScheme.background,
|
||||||
|
),
|
||||||
|
'th': Style(
|
||||||
|
padding: HtmlPaddings.only(left: 3, right: 3),
|
||||||
|
),
|
||||||
|
'td': Style(
|
||||||
|
padding: HtmlPaddings.all(4.0),
|
||||||
|
alignment: Alignment.center,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import 'package:pilipala/common/widgets/stat/danmu.dart';
|
|||||||
import 'package:pilipala/common/widgets/stat/view.dart';
|
import 'package:pilipala/common/widgets/stat/view.dart';
|
||||||
import 'package:pilipala/http/search.dart';
|
import 'package:pilipala/http/search.dart';
|
||||||
import 'package:pilipala/http/user.dart';
|
import 'package:pilipala/http/user.dart';
|
||||||
|
import 'package:pilipala/pages/member/index.dart';
|
||||||
import 'package:pilipala/utils/utils.dart';
|
import 'package:pilipala/utils/utils.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
|
|
||||||
@ -17,10 +18,6 @@ class VideoCardH extends StatelessWidget {
|
|||||||
final Function()? longPress;
|
final Function()? longPress;
|
||||||
final Function()? longPressEnd;
|
final Function()? longPressEnd;
|
||||||
final String source;
|
final String source;
|
||||||
final bool showOwner;
|
|
||||||
final bool showView;
|
|
||||||
final bool showDanmaku;
|
|
||||||
final bool showPubdate;
|
|
||||||
|
|
||||||
const VideoCardH({
|
const VideoCardH({
|
||||||
Key? key,
|
Key? key,
|
||||||
@ -28,10 +25,6 @@ class VideoCardH extends StatelessWidget {
|
|||||||
this.longPress,
|
this.longPress,
|
||||||
this.longPressEnd,
|
this.longPressEnd,
|
||||||
this.source = 'normal',
|
this.source = 'normal',
|
||||||
this.showOwner = true,
|
|
||||||
this.showView = true,
|
|
||||||
this.showDanmaku = true,
|
|
||||||
this.showPubdate = false,
|
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -41,9 +34,10 @@ class VideoCardH extends StatelessWidget {
|
|||||||
String heroTag = Utils.makeHeroTag(aid);
|
String heroTag = Utils.makeHeroTag(aid);
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onLongPress: () {
|
onLongPress: () {
|
||||||
if (longPress != null) {
|
// if (longPress != null) {
|
||||||
longPress!();
|
// longPress!();
|
||||||
}
|
// }
|
||||||
|
MemberController().blockUser(videoItem.mid);
|
||||||
},
|
},
|
||||||
// onLongPressEnd: (details) {
|
// onLongPressEnd: (details) {
|
||||||
// if (longPressEnd != null) {
|
// if (longPressEnd != null) {
|
||||||
@ -111,14 +105,7 @@ class VideoCardH extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
VideoContent(
|
VideoContent(videoItem: videoItem, source: source)
|
||||||
videoItem: videoItem,
|
|
||||||
source: source,
|
|
||||||
showOwner: showOwner,
|
|
||||||
showView: showView,
|
|
||||||
showDanmaku: showDanmaku,
|
|
||||||
showPubdate: showPubdate,
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -134,20 +121,8 @@ class VideoContent extends StatelessWidget {
|
|||||||
// ignore: prefer_typing_uninitialized_variables
|
// ignore: prefer_typing_uninitialized_variables
|
||||||
final videoItem;
|
final videoItem;
|
||||||
final String source;
|
final String source;
|
||||||
final bool showOwner;
|
const VideoContent(
|
||||||
final bool showView;
|
{super.key, required this.videoItem, this.source = 'normal'});
|
||||||
final bool showDanmaku;
|
|
||||||
final bool showPubdate;
|
|
||||||
|
|
||||||
const VideoContent({
|
|
||||||
super.key,
|
|
||||||
required this.videoItem,
|
|
||||||
this.source = 'normal',
|
|
||||||
this.showOwner = true,
|
|
||||||
this.showView = true,
|
|
||||||
this.showDanmaku = true,
|
|
||||||
this.showPubdate = false,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -206,61 +181,16 @@ class VideoContent extends StatelessWidget {
|
|||||||
// ),
|
// ),
|
||||||
// ),
|
// ),
|
||||||
// const SizedBox(height: 4),
|
// const SizedBox(height: 4),
|
||||||
if (showPubdate)
|
|
||||||
Text(
|
|
||||||
Utils.dateFormat(videoItem.pubdate!),
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 11, color: Theme.of(context).colorScheme.outline),
|
|
||||||
),
|
|
||||||
if (showOwner)
|
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
videoItem.owner.name,
|
videoItem.owner.name,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize:
|
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
|
||||||
Theme.of(context).textTheme.labelMedium!.fontSize,
|
|
||||||
color: Theme.of(context).colorScheme.outline,
|
color: Theme.of(context).colorScheme.outline,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
if (showView) ...[
|
|
||||||
StatView(
|
|
||||||
theme: 'gray',
|
|
||||||
view: videoItem.stat.view,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
],
|
|
||||||
if (showDanmaku)
|
|
||||||
StatDanMu(
|
|
||||||
theme: 'gray',
|
|
||||||
danmu: videoItem.stat.danmaku,
|
|
||||||
),
|
|
||||||
|
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
// SizedBox(
|
|
||||||
// width: 20,
|
|
||||||
// height: 20,
|
|
||||||
// child: IconButton(
|
|
||||||
// tooltip: '稍后再看',
|
|
||||||
// style: ButtonStyle(
|
|
||||||
// padding: MaterialStateProperty.all(EdgeInsets.zero),
|
|
||||||
// ),
|
|
||||||
// onPressed: () async {
|
|
||||||
// var res =
|
|
||||||
// await UserHttp.toViewLater(bvid: videoItem.bvid);
|
|
||||||
// SmartDialog.showToast(res['msg']);
|
|
||||||
// },
|
|
||||||
// icon: Icon(
|
|
||||||
// Icons.more_vert_outlined,
|
|
||||||
// color: Theme.of(context).colorScheme.outline,
|
|
||||||
// size: 14,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
if (source == 'normal')
|
if (source == 'normal')
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 24,
|
width: 24,
|
||||||
@ -294,6 +224,20 @@ class VideoContent extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
// PopupMenuItem<String>(
|
||||||
|
// onTap: () async {
|
||||||
|
// MemberController().blockUser(videoItem.mid);
|
||||||
|
// },
|
||||||
|
// value: 'block',
|
||||||
|
// height: 35,
|
||||||
|
// child: const Row(
|
||||||
|
// children: [
|
||||||
|
// Icon(Icons.block, size: 16),
|
||||||
|
// SizedBox(width: 6),
|
||||||
|
// Text('拉黑up', style: TextStyle(fontSize: 13))
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -5,7 +5,6 @@ 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/stat/danmu.dart';
|
import 'package:pilipala/common/widgets/stat/danmu.dart';
|
||||||
import 'package:pilipala/common/widgets/stat/view.dart';
|
import 'package:pilipala/common/widgets/stat/view.dart';
|
||||||
import 'package:pilipala/http/dynamics.dart';
|
|
||||||
import 'package:pilipala/http/search.dart';
|
import 'package:pilipala/http/search.dart';
|
||||||
import 'package:pilipala/http/user.dart';
|
import 'package:pilipala/http/user.dart';
|
||||||
import 'package:pilipala/models/common/search_type.dart';
|
import 'package:pilipala/models/common/search_type.dart';
|
||||||
@ -28,11 +27,6 @@ class VideoCardV extends StatelessWidget {
|
|||||||
this.longPressEnd,
|
this.longPressEnd,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
bool isStringNumeric(String str) {
|
|
||||||
RegExp numericRegex = RegExp(r'^\d+$');
|
|
||||||
return numericRegex.hasMatch(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
void onPushDetail(heroTag) async {
|
void onPushDetail(heroTag) async {
|
||||||
String goto = videoItem.goto;
|
String goto = videoItem.goto;
|
||||||
switch (goto) {
|
switch (goto) {
|
||||||
@ -54,7 +48,7 @@ class VideoCardV extends StatelessWidget {
|
|||||||
arguments: {
|
arguments: {
|
||||||
'pic': videoItem.pic,
|
'pic': videoItem.pic,
|
||||||
'heroTag': heroTag,
|
'heroTag': heroTag,
|
||||||
'videoType': SearchType.media_bangumi,
|
// 'videoType': SearchType.media_bangumi,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -68,47 +62,6 @@ class VideoCardV extends StatelessWidget {
|
|||||||
'heroTag': heroTag,
|
'heroTag': heroTag,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
// 动态
|
|
||||||
case 'picture':
|
|
||||||
try {
|
|
||||||
String dynamicType = 'picture';
|
|
||||||
String uri = videoItem.uri;
|
|
||||||
String id = '';
|
|
||||||
if (videoItem.uri.startsWith('bilibili://article/')) {
|
|
||||||
// https://www.bilibili.com/read/cv27063554
|
|
||||||
dynamicType = 'read';
|
|
||||||
RegExp regex = RegExp(r'\d+');
|
|
||||||
Match match = regex.firstMatch(videoItem.uri)!;
|
|
||||||
String matchedNumber = match.group(0)!;
|
|
||||||
videoItem.param = int.parse(matchedNumber);
|
|
||||||
id = 'cv${videoItem.param}';
|
|
||||||
}
|
|
||||||
if (uri.startsWith('http')) {
|
|
||||||
String path = Uri.parse(uri).path;
|
|
||||||
if (isStringNumeric(path.split('/')[1])) {
|
|
||||||
// 请求接口
|
|
||||||
var res =
|
|
||||||
await DynamicsHttp.dynamicDetail(id: path.split('/')[1]);
|
|
||||||
if (res['status']) {
|
|
||||||
Get.toNamed('/dynamicDetail', arguments: {
|
|
||||||
'item': res['data'],
|
|
||||||
'floor': 1,
|
|
||||||
'action': 'detail'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Get.toNamed('/htmlRender', parameters: {
|
|
||||||
'url': uri,
|
|
||||||
'title': videoItem.title,
|
|
||||||
'id': id,
|
|
||||||
'dynamicType': dynamicType
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
SmartDialog.showToast(err.toString());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
SmartDialog.showToast(videoItem.goto);
|
SmartDialog.showToast(videoItem.goto);
|
||||||
Get.toNamed(
|
Get.toNamed(
|
||||||
@ -325,20 +278,23 @@ class VideoStat extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return RichText(
|
return Row(
|
||||||
maxLines: 1,
|
children: [
|
||||||
text: TextSpan(
|
Text(
|
||||||
|
'${videoItem.stat.view}观看',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize,
|
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize,
|
||||||
color: Theme.of(context).colorScheme.outline,
|
color: Theme.of(context).colorScheme.outline,
|
||||||
),
|
),
|
||||||
children: [
|
|
||||||
if (videoItem.stat.view != '-')
|
|
||||||
TextSpan(text: '${videoItem.stat.view}观看'),
|
|
||||||
if (videoItem.stat.danmu != '-')
|
|
||||||
TextSpan(text: ' • ${videoItem.stat.danmu}弹幕'),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
|
Text(
|
||||||
|
' • ${videoItem.stat.danmu}弹幕',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize,
|
||||||
|
color: Theme.of(context).colorScheme.outline,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -97,9 +97,6 @@ class Api {
|
|||||||
// 操作用户关系
|
// 操作用户关系
|
||||||
static const String relationMod = '/x/relation/modify';
|
static const String relationMod = '/x/relation/modify';
|
||||||
|
|
||||||
// 相互关系查询 // 失效
|
|
||||||
// static const String relationSearch = '/x/space/wbi/acc/relation';
|
|
||||||
|
|
||||||
// 评论列表
|
// 评论列表
|
||||||
// https://api.bilibili.com/x/v2/reply/main?csrf=6e22efc1a47225ea25f901f922b5cfdd&mode=3&oid=254175381&pagination_str=%7B%22offset%22:%22%22%7D&plat=1&seek_rpid=0&type=11
|
// https://api.bilibili.com/x/v2/reply/main?csrf=6e22efc1a47225ea25f901f922b5cfdd&mode=3&oid=254175381&pagination_str=%7B%22offset%22:%22%22%7D&plat=1&seek_rpid=0&type=11
|
||||||
static const String replyList = '/x/v2/reply';
|
static const String replyList = '/x/v2/reply';
|
||||||
@ -129,14 +126,12 @@ class Api {
|
|||||||
static const String userFavFolder = '/x/v3/fav/folder/created/list';
|
static const String userFavFolder = '/x/v3/fav/folder/created/list';
|
||||||
|
|
||||||
/// 收藏夹 详情
|
/// 收藏夹 详情
|
||||||
/// media_id 当前收藏夹id 搜索全部时为默认收藏夹id
|
/// media_id int 收藏夹id
|
||||||
/// pn int 当前页
|
/// pn int 当前页
|
||||||
/// ps int pageSize
|
/// ps int pageSize
|
||||||
/// keyword String 搜索词
|
/// keyword String 搜索词
|
||||||
/// order String 排序方式 view 最多播放 mtime 最近收藏 pubtime 最近投稿
|
/// order String 排序方式 view 最多播放 mtime 最近收藏 pubtime 最近投稿
|
||||||
/// tid int 分区id
|
/// tid int 分区id
|
||||||
/// platform web
|
|
||||||
/// type 0 当前收藏夹 1 全部收藏夹
|
|
||||||
// https://api.bilibili.com/x/v3/fav/resource/list?media_id=76614671&pn=1&ps=20&keyword=&order=mtime&type=0&tid=0
|
// https://api.bilibili.com/x/v3/fav/resource/list?media_id=76614671&pn=1&ps=20&keyword=&order=mtime&type=0&tid=0
|
||||||
static const String userFavFolderDetail = '/x/v3/fav/resource/list';
|
static const String userFavFolderDetail = '/x/v3/fav/resource/list';
|
||||||
|
|
||||||
@ -172,9 +167,6 @@ class Api {
|
|||||||
// 删除某条历史记录
|
// 删除某条历史记录
|
||||||
static const String delHistory = '/x/v2/history/delete';
|
static const String delHistory = '/x/v2/history/delete';
|
||||||
|
|
||||||
// 搜索历史记录
|
|
||||||
static const String searchHistory = '/x/web-goblin/history/search';
|
|
||||||
|
|
||||||
// 热搜
|
// 热搜
|
||||||
static const String hotSearchList =
|
static const String hotSearchList =
|
||||||
'https://s.search.bilibili.com/main/hotword';
|
'https://s.search.bilibili.com/main/hotword';
|
||||||
@ -215,7 +207,7 @@ class Api {
|
|||||||
// 粉丝
|
// 粉丝
|
||||||
// vmid 用户id pn 页码 ps 每页个数,最大50 order: desc
|
// vmid 用户id pn 页码 ps 每页个数,最大50 order: desc
|
||||||
// order_type 排序规则 最近访问传空,最常访问传 attention
|
// order_type 排序规则 最近访问传空,最常访问传 attention
|
||||||
static const String fans = '/x/relation/fans';
|
static const String fans = 'https://api.bilibili.com/x/relation/fans';
|
||||||
|
|
||||||
// 直播
|
// 直播
|
||||||
// ?page=1&page_size=30&platform=web
|
// ?page=1&page_size=30&platform=web
|
||||||
@ -312,158 +304,6 @@ class Api {
|
|||||||
|
|
||||||
static const String webDanmaku = '/x/v2/dm/web/seg.so';
|
static const String webDanmaku = '/x/v2/dm/web/seg.so';
|
||||||
|
|
||||||
//发送视频弹幕
|
// 搜索历史记录
|
||||||
//https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/danmaku/action.md
|
static const String searchHistory = '/x/web-goblin/history/search';
|
||||||
static const String shootDanmaku = '/x/v2/dm/post';
|
|
||||||
|
|
||||||
// up主分组
|
|
||||||
static const String followUpTag = '/x/relation/tags';
|
|
||||||
|
|
||||||
// 设置Up主分组
|
|
||||||
// 0 添加至默认分组 否则使用,分割tagid
|
|
||||||
static const String addUsers = '/x/relation/tags/addUsers';
|
|
||||||
|
|
||||||
// 获取指定分组下的up
|
|
||||||
static const String followUpGroup = '/x/relation/tag';
|
|
||||||
|
|
||||||
/// 私聊
|
|
||||||
/// 'https://api.vc.bilibili.com/session_svr/v1/session_svr/get_sessions?
|
|
||||||
/// session_type=1&
|
|
||||||
/// group_fold=1&
|
|
||||||
/// unfollow_fold=0&
|
|
||||||
/// sort_rule=2&
|
|
||||||
/// build=0&
|
|
||||||
/// mobi_app=web&
|
|
||||||
/// w_rid=8641d157fb9a9255eb2159f316ee39e2&
|
|
||||||
/// wts=1697305010
|
|
||||||
|
|
||||||
static const String sessionList =
|
|
||||||
'https://api.vc.bilibili.com/session_svr/v1/session_svr/get_sessions';
|
|
||||||
|
|
||||||
/// 私聊用户信息
|
|
||||||
/// uids
|
|
||||||
/// build=0&mobi_app=web
|
|
||||||
static const String sessionAccountList =
|
|
||||||
'https://api.vc.bilibili.com/account/v1/user/cards';
|
|
||||||
|
|
||||||
/// https://api.vc.bilibili.com/svr_sync/v1/svr_sync/fetch_session_msgs?
|
|
||||||
/// talker_id=400787461&
|
|
||||||
/// session_type=1&
|
|
||||||
/// size=20&
|
|
||||||
/// sender_device_id=1&
|
|
||||||
/// build=0&
|
|
||||||
/// mobi_app=web&
|
|
||||||
/// web_location=333.1296&
|
|
||||||
/// w_rid=cfe3bf58c9fe181bbf4dd6c75175e6b0&
|
|
||||||
/// wts=1697350697
|
|
||||||
|
|
||||||
static const String sessionMsg =
|
|
||||||
'https://api.vc.bilibili.com/svr_sync/v1/svr_sync/fetch_session_msgs';
|
|
||||||
|
|
||||||
/// 标记已读 POST
|
|
||||||
/// talker_id:
|
|
||||||
/// session_type: 1
|
|
||||||
/// ack_seqno: 920224140918926
|
|
||||||
/// build: 0
|
|
||||||
/// mobi_app: web
|
|
||||||
/// csrf_token:
|
|
||||||
/// csrf:
|
|
||||||
static const String updateAck =
|
|
||||||
'https://api.vc.bilibili.com/session_svr/v1/session_svr/update_ack';
|
|
||||||
|
|
||||||
// 获取某个动态详情
|
|
||||||
// timezone_offset=-480
|
|
||||||
// id=849312409672744983
|
|
||||||
// features=itemOpusStyle
|
|
||||||
static const String dynamicDetail = '/x/polymer/web-dynamic/v1/detail';
|
|
||||||
|
|
||||||
// AI总结
|
|
||||||
/// https://api.bilibili.com/x/web-interface/view/conclusion/get?
|
|
||||||
/// bvid=BV1ju4y1s7kn&
|
|
||||||
/// cid=1296086601&
|
|
||||||
/// up_mid=4641697&
|
|
||||||
/// w_rid=1607c6c5a4a35a1297e31992220900ae&
|
|
||||||
/// wts=1697033079
|
|
||||||
static const String aiConclusion = '/x/web-interface/view/conclusion/get';
|
|
||||||
|
|
||||||
// captcha验证码
|
|
||||||
static const String getCaptcha =
|
|
||||||
'https://passport.bilibili.com/x/passport-login/captcha?source=main_web';
|
|
||||||
|
|
||||||
// web端短信验证码
|
|
||||||
static const String smsCode =
|
|
||||||
'https://passport.bilibili.com/x/passport-login/web/sms/send';
|
|
||||||
|
|
||||||
// web端验证码登录
|
|
||||||
|
|
||||||
// web端密码登录
|
|
||||||
|
|
||||||
// app端短信验证码
|
|
||||||
static const String appSmsCode =
|
|
||||||
'https://passport.bilibili.com/x/passport-login/sms/send';
|
|
||||||
|
|
||||||
// app端验证码登录
|
|
||||||
|
|
||||||
// 获取短信验证码
|
|
||||||
// static const String appSafeSmsCode =
|
|
||||||
// 'https://passport.bilibili.com/x/safecenter/common/sms/send';
|
|
||||||
|
|
||||||
/// app端密码登录
|
|
||||||
/// username
|
|
||||||
/// password
|
|
||||||
/// key
|
|
||||||
/// rhash
|
|
||||||
static const String loginInByPwdApi =
|
|
||||||
'https://passport.bilibili.com/x/passport-login/oauth2/login';
|
|
||||||
|
|
||||||
/// 密码加密密钥
|
|
||||||
/// disable_rcmd
|
|
||||||
/// local_id
|
|
||||||
static const getWebKey =
|
|
||||||
'https://passport.bilibili.com/x/passport-login/web/key';
|
|
||||||
|
|
||||||
/// cookie转access_key
|
|
||||||
static const cookieToKey =
|
|
||||||
'https://passport.bilibili.com/x/passport-tv-login/h5/qrcode/confirm';
|
|
||||||
|
|
||||||
/// 申请二维码(TV端)
|
|
||||||
static const getTVCode =
|
|
||||||
'https://passport.snm0516.aisee.tv/x/passport-tv-login/qrcode/auth_code';
|
|
||||||
|
|
||||||
///扫码登录(TV端)
|
|
||||||
static const qrcodePoll =
|
|
||||||
'https://passport.bilibili.com/x/passport-tv-login/qrcode/poll';
|
|
||||||
|
|
||||||
/// 置顶视频
|
|
||||||
static const getTopVideoApi = '/x/space/top/arc';
|
|
||||||
|
|
||||||
/// 主页 - 最近投币的视频
|
|
||||||
/// vmid
|
|
||||||
/// gaia_source = main_web
|
|
||||||
/// web_location
|
|
||||||
/// w_rid
|
|
||||||
/// wts
|
|
||||||
static const getRecentCoinVideoApi = '/x/space/coin/video';
|
|
||||||
|
|
||||||
/// 最近点赞的视频
|
|
||||||
static const getRecentLikeVideoApi = '/x/space/like/video';
|
|
||||||
|
|
||||||
/// 最近追番
|
|
||||||
static const getRecentBangumiApi = '/x/space/bangumi/follow/list';
|
|
||||||
|
|
||||||
/// 用户专栏
|
|
||||||
static const getMemberSeasonsApi = '/x/polymer/web-space/home/seasons_series';
|
|
||||||
|
|
||||||
/// 获赞数 播放数
|
|
||||||
/// mid
|
|
||||||
static const getMemberViewApi = '/x/space/upstat';
|
|
||||||
|
|
||||||
/// 查询某个专栏
|
|
||||||
/// mid
|
|
||||||
/// season_id
|
|
||||||
/// sort_reverse
|
|
||||||
/// page_num
|
|
||||||
/// page_size
|
|
||||||
static const getSeasonDetailApi =
|
|
||||||
'/x/polymer/web-space/seasons_archives_list';
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,37 +2,4 @@ class HttpString {
|
|||||||
static const String baseUrl = 'https://www.bilibili.com';
|
static const String baseUrl = 'https://www.bilibili.com';
|
||||||
static const String baseApiUrl = 'https://api.bilibili.com';
|
static const String baseApiUrl = 'https://api.bilibili.com';
|
||||||
static const String tUrl = 'https://api.vc.bilibili.com';
|
static const String tUrl = 'https://api.vc.bilibili.com';
|
||||||
static const List<int> validateStatusCodes = [
|
|
||||||
302,
|
|
||||||
304,
|
|
||||||
307,
|
|
||||||
400,
|
|
||||||
401,
|
|
||||||
403,
|
|
||||||
404,
|
|
||||||
405,
|
|
||||||
409,
|
|
||||||
412,
|
|
||||||
500,
|
|
||||||
503,
|
|
||||||
504,
|
|
||||||
509,
|
|
||||||
616,
|
|
||||||
617,
|
|
||||||
625,
|
|
||||||
626,
|
|
||||||
628,
|
|
||||||
629,
|
|
||||||
632,
|
|
||||||
643,
|
|
||||||
650,
|
|
||||||
652,
|
|
||||||
658,
|
|
||||||
662,
|
|
||||||
688,
|
|
||||||
689,
|
|
||||||
701,
|
|
||||||
799,
|
|
||||||
8888
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,9 @@ class DanmakaHttp {
|
|||||||
'oid': cid,
|
'oid': cid,
|
||||||
'segment_index': segmentIndex,
|
'segment_index': segmentIndex,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 计算函数
|
||||||
|
Future<DmSegMobileReply> computeTask(Map<String, int> params) async {
|
||||||
var response = await Request().get(
|
var response = await Request().get(
|
||||||
Api.webDanmaku,
|
Api.webDanmaku,
|
||||||
data: params,
|
data: params,
|
||||||
@ -24,72 +27,7 @@ class DanmakaHttp {
|
|||||||
);
|
);
|
||||||
return DmSegMobileReply.fromBuffer(response.data);
|
return DmSegMobileReply.fromBuffer(response.data);
|
||||||
}
|
}
|
||||||
static Future shootDanmaku({
|
|
||||||
int type = 1,//弹幕类选择(1:视频弹幕 2:漫画弹幕)
|
|
||||||
required int oid,// 视频cid
|
|
||||||
required String msg,//弹幕文本(长度小于 100 字符)
|
|
||||||
int mode = 1,// 弹幕类型(1:滚动弹幕 4:底端弹幕 5:顶端弹幕 6:逆向弹幕(不能使用) 7:高级弹幕 8:代码弹幕(不能使用) 9:BAS弹幕(pool必须为2))
|
|
||||||
// String? aid,// 稿件avid
|
|
||||||
// String? bvid,// bvid与aid必须有一个
|
|
||||||
required String bvid,
|
|
||||||
int? progress,// 弹幕出现在视频内的时间(单位为毫秒,默认为0)
|
|
||||||
int? color,// 弹幕颜色(默认白色,16777215)
|
|
||||||
int? fontsize,// 弹幕字号(默认25)
|
|
||||||
int? pool,// 弹幕池选择(0:普通池 1:字幕池 2:特殊池(代码/BAS弹幕)默认普通池,0)
|
|
||||||
//int? rnd,// 当前时间戳*1000000(若无此项,则发送弹幕冷却时间限制为90s;若有此项,则发送弹幕冷却时间限制为5s)
|
|
||||||
int? colorful,//60001:专属渐变彩色(需要会员)
|
|
||||||
int? checkbox_type,//是否带 UP 身份标识(0:普通;4:带有标识)
|
|
||||||
// String? csrf,//CSRF Token(位于 Cookie) Cookie 方式必要
|
|
||||||
// String? access_key,// APP 登录 Token APP 方式必要
|
|
||||||
}) async {
|
|
||||||
// 构建参数对象
|
|
||||||
// assert(aid != null || bvid != null);
|
|
||||||
// assert(csrf != null || access_key != null);
|
|
||||||
assert(msg.length < 100);
|
|
||||||
// 构建参数对象
|
|
||||||
var params = <String, dynamic>{
|
|
||||||
'type': type,
|
|
||||||
'oid': oid,
|
|
||||||
'msg': msg,
|
|
||||||
'mode': mode,
|
|
||||||
//'aid': aid,
|
|
||||||
'bvid': bvid,
|
|
||||||
'progress': progress,
|
|
||||||
'color': color,
|
|
||||||
'fontsize': fontsize,
|
|
||||||
'pool': pool,
|
|
||||||
'rnd': DateTime.now().microsecondsSinceEpoch,
|
|
||||||
'colorful': colorful,
|
|
||||||
'checkbox_type': checkbox_type,
|
|
||||||
'csrf': await Request.getCsrf(),
|
|
||||||
// 'access_key': access_key,
|
|
||||||
}..removeWhere((key, value) => value == null);
|
|
||||||
|
|
||||||
var response = await Request().post(
|
return await compute(computeTask, params);
|
||||||
Api.shootDanmaku,
|
|
||||||
data: params,
|
|
||||||
options: Options(
|
|
||||||
contentType: Headers.formUrlEncodedContentType,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (response.statusCode != 200) {
|
|
||||||
return {
|
|
||||||
'status': false,
|
|
||||||
'data': [],
|
|
||||||
'msg': '弹幕发送失败,状态码:${response.statusCode}',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
if (response.data['code'] == 0) {
|
|
||||||
return {
|
|
||||||
'status': true,
|
|
||||||
'data': response.data['data'],
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
'status': false,
|
|
||||||
'data': [],
|
|
||||||
'msg': "${response.data['code']}: ${response.data['message']}",
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,6 @@ class DynamicsHttp {
|
|||||||
'data': DynamicsDataModel.fromJson(res.data['data']),
|
'data': DynamicsDataModel.fromJson(res.data['data']),
|
||||||
};
|
};
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
print(err);
|
|
||||||
return {
|
return {
|
||||||
'status': false,
|
'status': false,
|
||||||
'data': [],
|
'data': [],
|
||||||
@ -86,35 +85,4 @@ class DynamicsHttp {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
|
||||||
static Future dynamicDetail({
|
|
||||||
String? id,
|
|
||||||
}) async {
|
|
||||||
var res = await Request().get(Api.dynamicDetail, data: {
|
|
||||||
'timezone_offset': -480,
|
|
||||||
'id': id,
|
|
||||||
'features': 'itemOpusStyle',
|
|
||||||
});
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
try {
|
|
||||||
return {
|
|
||||||
'status': true,
|
|
||||||
'data': DynamicItemModel.fromJson(res.data['data']['item']),
|
|
||||||
};
|
|
||||||
} catch (err) {
|
|
||||||
return {
|
|
||||||
'status': false,
|
|
||||||
'data': [],
|
|
||||||
'msg': err.toString(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
'status': false,
|
|
||||||
'data': [],
|
|
||||||
'msg': res.data['message'],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,35 +3,17 @@ import 'package:html/parser.dart';
|
|||||||
import 'package:pilipala/http/index.dart';
|
import 'package:pilipala/http/index.dart';
|
||||||
|
|
||||||
class HtmlHttp {
|
class HtmlHttp {
|
||||||
// article
|
static Future reqHtml(id) async {
|
||||||
static Future reqHtml(id, dynamicType) async {
|
var response = await Request().get("https://www.bilibili.com/opus/$id");
|
||||||
var response = await Request().get(
|
|
||||||
"https://www.bilibili.com/opus/$id",
|
|
||||||
extra: {'ua': 'pc'},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (response.data.contains('Redirecting to')) {
|
|
||||||
RegExp regex = RegExp(r'//([\w\.]+)/(\w+)/(\w+)');
|
|
||||||
Match match = regex.firstMatch(response.data)!;
|
|
||||||
String matchedString = match.group(0)!;
|
|
||||||
response = await Request().get(
|
|
||||||
'https:$matchedString' + '/',
|
|
||||||
extra: {'ua': 'pc'},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Document rootTree = parse(response.data);
|
Document rootTree = parse(response.data);
|
||||||
// log(response.data.body.toString());
|
|
||||||
Element body = rootTree.body!;
|
Element body = rootTree.body!;
|
||||||
Element appDom = body.querySelector('#app')!;
|
Element appDom = body.querySelector('#app')!;
|
||||||
Element authorHeader = appDom.querySelector('.fixed-author-header')!;
|
Element authorHeader = appDom.querySelector('.fixed-author-header')!;
|
||||||
// 头像
|
// 头像
|
||||||
String avatar = authorHeader.querySelector('img')!.attributes['src']!;
|
String avatar = authorHeader.querySelector('img')!.attributes['src']!;
|
||||||
avatar = 'https:${avatar.split('@')[0]}';
|
avatar = 'https:${avatar.split('@')[0]}';
|
||||||
String uname = authorHeader
|
String uname =
|
||||||
.querySelector('.fixed-author-header__author__name')!
|
authorHeader.querySelector('.fixed-author-header__author__name')!.text;
|
||||||
.text;
|
|
||||||
|
|
||||||
// 动态详情
|
// 动态详情
|
||||||
Element opusDetail = appDom.querySelector('.opus-detail')!;
|
Element opusDetail = appDom.querySelector('.opus-detail')!;
|
||||||
// 发布时间
|
// 发布时间
|
||||||
@ -40,9 +22,6 @@ class HtmlHttp {
|
|||||||
//
|
//
|
||||||
String opusContent =
|
String opusContent =
|
||||||
opusDetail.querySelector('.opus-module-content')!.innerHtml;
|
opusDetail.querySelector('.opus-module-content')!.innerHtml;
|
||||||
String test = opusDetail
|
|
||||||
.querySelector('.horizontal-scroll-album__pic__img')!
|
|
||||||
.innerHtml;
|
|
||||||
String commentId = opusDetail
|
String commentId = opusDetail
|
||||||
.querySelector('.bili-comment-container')!
|
.querySelector('.bili-comment-container')!
|
||||||
.className
|
.className
|
||||||
@ -54,50 +33,8 @@ class HtmlHttp {
|
|||||||
'avatar': avatar,
|
'avatar': avatar,
|
||||||
'uname': uname,
|
'uname': uname,
|
||||||
'updateTime': updateTime,
|
'updateTime': updateTime,
|
||||||
'content': test + opusContent,
|
|
||||||
'commentId': int.parse(commentId)
|
|
||||||
};
|
|
||||||
} catch (err) {
|
|
||||||
print('err: $err');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// read
|
|
||||||
static Future reqReadHtml(id, dynamicType) async {
|
|
||||||
var response = await Request().get(
|
|
||||||
"https://www.bilibili.com/$dynamicType/$id/",
|
|
||||||
extra: {'ua': 'pc'},
|
|
||||||
);
|
|
||||||
Document rootTree = parse(response.data);
|
|
||||||
Element body = rootTree.body!;
|
|
||||||
Element appDom = body.querySelector('#app')!;
|
|
||||||
Element authorHeader = appDom.querySelector('.up-left')!;
|
|
||||||
// 头像
|
|
||||||
// String avatar =
|
|
||||||
// authorHeader.querySelector('.bili-avatar-img')!.attributes['data-src']!;
|
|
||||||
// print(avatar);
|
|
||||||
// avatar = 'https:${avatar.split('@')[0]}';
|
|
||||||
String uname = authorHeader.querySelector('.up-name')!.text.trim();
|
|
||||||
// 动态详情
|
|
||||||
Element opusDetail = appDom.querySelector('.article-content')!;
|
|
||||||
// 发布时间
|
|
||||||
// String updateTime =
|
|
||||||
// opusDetail.querySelector('.opus-module-author__pub__text')!.text;
|
|
||||||
// print(updateTime);
|
|
||||||
|
|
||||||
//
|
|
||||||
String opusContent =
|
|
||||||
opusDetail.querySelector('#read-article-holder')!.innerHtml;
|
|
||||||
RegExp digitRegExp = RegExp(r'\d+');
|
|
||||||
Iterable<Match> matches = digitRegExp.allMatches(id);
|
|
||||||
String number = matches.first.group(0)!;
|
|
||||||
return {
|
|
||||||
'status': true,
|
|
||||||
'avatar': '',
|
|
||||||
'uname': uname,
|
|
||||||
'updateTime': '',
|
|
||||||
'content': opusContent,
|
'content': opusContent,
|
||||||
'commentId': int.parse(number)
|
'commentId': commentId
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,6 @@ import 'dart:io';
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:cookie_jar/cookie_jar.dart';
|
import 'package:cookie_jar/cookie_jar.dart';
|
||||||
import 'package:dio/io.dart';
|
|
||||||
import 'package:dio_http2_adapter/dio_http2_adapter.dart';
|
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
import 'package:pilipala/utils/utils.dart';
|
import 'package:pilipala/utils/utils.dart';
|
||||||
@ -18,11 +16,6 @@ class Request {
|
|||||||
static late CookieManager cookieManager;
|
static late CookieManager cookieManager;
|
||||||
static late final Dio dio;
|
static late final Dio dio;
|
||||||
factory Request() => _instance;
|
factory Request() => _instance;
|
||||||
Box setting = GStrorage.setting;
|
|
||||||
static Box localCache = GStrorage.localCache;
|
|
||||||
late dynamic enableSystemProxy;
|
|
||||||
late String systemProxyHost;
|
|
||||||
late String systemProxyPort;
|
|
||||||
|
|
||||||
/// 设置cookie
|
/// 设置cookie
|
||||||
static setCookie() async {
|
static setCookie() async {
|
||||||
@ -47,8 +40,8 @@ class Request {
|
|||||||
log("setCookie, ${e.toString()}");
|
log("setCookie, ${e.toString()}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setOptionsHeaders(userInfo);
|
||||||
}
|
}
|
||||||
setOptionsHeaders(userInfo, userInfo != null && userInfo.mid != null);
|
|
||||||
|
|
||||||
if (cookie.isEmpty) {
|
if (cookie.isEmpty) {
|
||||||
try {
|
try {
|
||||||
@ -66,6 +59,9 @@ class Request {
|
|||||||
static Future<String> getCsrf() async {
|
static Future<String> getCsrf() async {
|
||||||
var cookies = await cookieManager.cookieJar
|
var cookies = await cookieManager.cookieJar
|
||||||
.loadForRequest(Uri.parse(HttpString.baseApiUrl));
|
.loadForRequest(Uri.parse(HttpString.baseApiUrl));
|
||||||
|
// for (var i in cookies) {
|
||||||
|
// print(i);
|
||||||
|
// }
|
||||||
String token = '';
|
String token = '';
|
||||||
if (cookies.where((e) => e.name == 'bili_jct').isNotEmpty) {
|
if (cookies.where((e) => e.name == 'bili_jct').isNotEmpty) {
|
||||||
token = cookies.firstWhere((e) => e.name == 'bili_jct').value;
|
token = cookies.firstWhere((e) => e.name == 'bili_jct').value;
|
||||||
@ -73,10 +69,8 @@ class Request {
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
static setOptionsHeaders(userInfo, status) {
|
static setOptionsHeaders(userInfo) {
|
||||||
if (status) {
|
|
||||||
dio.options.headers['x-bili-mid'] = userInfo.mid.toString();
|
dio.options.headers['x-bili-mid'] = userInfo.mid.toString();
|
||||||
}
|
|
||||||
dio.options.headers['env'] = 'prod';
|
dio.options.headers['env'] = 'prod';
|
||||||
dio.options.headers['app-key'] = 'android64';
|
dio.options.headers['app-key'] = 'android64';
|
||||||
dio.options.headers['x-bili-aurora-eid'] = 'UlMFQVcABlAH';
|
dio.options.headers['x-bili-aurora-eid'] = 'UlMFQVcABlAH';
|
||||||
@ -97,42 +91,15 @@ class Request {
|
|||||||
//响应流上前后两次接受到数据的间隔,单位为毫秒。
|
//响应流上前后两次接受到数据的间隔,单位为毫秒。
|
||||||
receiveTimeout: const Duration(milliseconds: 12000),
|
receiveTimeout: const Duration(milliseconds: 12000),
|
||||||
//Http请求头.
|
//Http请求头.
|
||||||
headers: {},
|
headers: {
|
||||||
);
|
'keep-alive': true,
|
||||||
|
'user-agent': headerUa('pc'),
|
||||||
enableSystemProxy =
|
'Accept-Encoding': 'gzip'
|
||||||
setting.get(SettingBoxKey.enableSystemProxy, defaultValue: false);
|
|
||||||
systemProxyHost =
|
|
||||||
localCache.get(LocalCacheKey.systemProxyHost, defaultValue: '');
|
|
||||||
systemProxyPort =
|
|
||||||
localCache.get(LocalCacheKey.systemProxyPort, defaultValue: '');
|
|
||||||
|
|
||||||
dio = Dio(options)
|
|
||||||
|
|
||||||
/// fix 第三方登录 302重定向 跟iOS代理问题冲突
|
|
||||||
..httpClientAdapter = Http2Adapter(
|
|
||||||
ConnectionManager(
|
|
||||||
idleTimeout: const Duration(milliseconds: 10000),
|
|
||||||
onClientCreate: (_, config) => config.onBadCertificate = (_) => true,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
/// 设置代理
|
|
||||||
if (enableSystemProxy) {
|
|
||||||
dio.httpClientAdapter = IOHttpClientAdapter(
|
|
||||||
createHttpClient: () {
|
|
||||||
final client = HttpClient();
|
|
||||||
// Config the client.
|
|
||||||
client.findProxy = (uri) {
|
|
||||||
// return 'PROXY host:port';
|
|
||||||
return 'PROXY $systemProxyHost:$systemProxyPort';
|
|
||||||
};
|
|
||||||
client.badCertificateCallback =
|
|
||||||
(X509Certificate cert, String host, int port) => true;
|
|
||||||
return client;
|
|
||||||
},
|
},
|
||||||
|
persistentConnection: true,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
dio = Dio(options);
|
||||||
|
|
||||||
//添加拦截器
|
//添加拦截器
|
||||||
dio.interceptors.add(ApiInterceptor());
|
dio.interceptors.add(ApiInterceptor());
|
||||||
@ -146,26 +113,30 @@ class Request {
|
|||||||
|
|
||||||
dio.transformer = BackgroundTransformer();
|
dio.transformer = BackgroundTransformer();
|
||||||
dio.options.validateStatus = (status) {
|
dio.options.validateStatus = (status) {
|
||||||
return status! >= 200 && status < 300 ||
|
return status! >= 200 && status < 300 || status == 304 || status == 302;
|
||||||
HttpString.validateStatusCodes.contains(status);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get请求
|
* get请求
|
||||||
*/
|
*/
|
||||||
get(url, {data, options, cancelToken, extra}) async {
|
get(url, {data, cacheOptions, options, cancelToken, extra}) async {
|
||||||
Response response;
|
Response response;
|
||||||
Options options = Options();
|
Options options;
|
||||||
|
String ua = 'pc';
|
||||||
ResponseType resType = ResponseType.json;
|
ResponseType resType = ResponseType.json;
|
||||||
if (extra != null) {
|
if (extra != null) {
|
||||||
|
ua = extra!['ua'] ?? 'pc';
|
||||||
resType = extra!['resType'] ?? ResponseType.json;
|
resType = extra!['resType'] ?? ResponseType.json;
|
||||||
if (extra['ua'] != null) {
|
|
||||||
options.headers = {'user-agent': headerUa(type: extra['ua'])};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (cacheOptions != null) {
|
||||||
|
cacheOptions.headers = {'user-agent': headerUa(ua)};
|
||||||
|
options = cacheOptions;
|
||||||
|
} else {
|
||||||
|
options = Options();
|
||||||
|
options.headers = {'user-agent': headerUa(ua)};
|
||||||
options.responseType = resType;
|
options.responseType = resType;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
response = await dio.get(
|
response = await dio.get(
|
||||||
url,
|
url,
|
||||||
@ -232,19 +203,15 @@ class Request {
|
|||||||
token.cancel("cancelled");
|
token.cancel("cancelled");
|
||||||
}
|
}
|
||||||
|
|
||||||
String headerUa({type = 'mob'}) {
|
String headerUa(ua) {
|
||||||
String headerUa = '';
|
String headerUa = '';
|
||||||
if (type == 'mob') {
|
if (ua == 'mob') {
|
||||||
if (Platform.isIOS) {
|
headerUa = Platform.isIOS
|
||||||
headerUa =
|
? 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1'
|
||||||
'Mozilla/5.0 (iPhone; CPU iPhone OS 14_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Mobile/15E148 Safari/604.1';
|
: 'Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.91 Mobile Safari/537.36';
|
||||||
} else {
|
} else {
|
||||||
headerUa =
|
headerUa =
|
||||||
'Mozilla/5.0 (Linux; Android 10; SM-G975F) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.101 Mobile Safari/537.36';
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 13_3_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.4 Safari/605.1.15';
|
||||||
}
|
|
||||||
} else {
|
|
||||||
headerUa =
|
|
||||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Safari/605.1.15';
|
|
||||||
}
|
}
|
||||||
return headerUa;
|
return headerUa;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,10 +46,7 @@ class ApiInterceptor extends Interceptor {
|
|||||||
void onError(DioException err, ErrorInterceptorHandler handler) async {
|
void onError(DioException err, ErrorInterceptorHandler handler) async {
|
||||||
// 处理网络请求错误
|
// 处理网络请求错误
|
||||||
// handler.next(err);
|
// handler.next(err);
|
||||||
SmartDialog.showToast(
|
SmartDialog.showToast(await dioError(err));
|
||||||
await dioError(err),
|
|
||||||
displayType: SmartToastType.onlyRefresh,
|
|
||||||
);
|
|
||||||
super.onError(err, handler);
|
super.onError(err, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,177 +0,0 @@
|
|||||||
import 'dart:convert';
|
|
||||||
import 'dart:math';
|
|
||||||
import 'package:crypto/crypto.dart';
|
|
||||||
|
|
||||||
import 'package:dio/dio.dart';
|
|
||||||
import 'package:encrypt/encrypt.dart';
|
|
||||||
import 'package:pilipala/http/index.dart';
|
|
||||||
import 'package:pilipala/models/login/index.dart';
|
|
||||||
import 'package:pilipala/utils/login.dart';
|
|
||||||
import 'package:uuid/uuid.dart';
|
|
||||||
|
|
||||||
class LoginHttp {
|
|
||||||
static Future queryCaptcha() async {
|
|
||||||
var res = await Request().get(Api.getCaptcha);
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
return {
|
|
||||||
'status': true,
|
|
||||||
'data': CaptchaDataModel.fromJson(res.data['data']),
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {'status': false, 'data': res.message};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future sendSmsCode({
|
|
||||||
int? cid,
|
|
||||||
required int tel,
|
|
||||||
required String token,
|
|
||||||
required String challenge,
|
|
||||||
required String validate,
|
|
||||||
required String seccode,
|
|
||||||
}) async {
|
|
||||||
var res = await Request().post(
|
|
||||||
Api.appSmsCode,
|
|
||||||
data: {
|
|
||||||
'cid': cid,
|
|
||||||
'tel': tel,
|
|
||||||
"source": "main_web",
|
|
||||||
'token': token,
|
|
||||||
'challenge': challenge,
|
|
||||||
'validate': validate,
|
|
||||||
'seccode': seccode,
|
|
||||||
},
|
|
||||||
options: Options(
|
|
||||||
contentType: Headers.formUrlEncodedContentType,
|
|
||||||
// headers: {'user-agent': ApiConstants.userAgent}
|
|
||||||
),
|
|
||||||
);
|
|
||||||
print(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
// web端验证码
|
|
||||||
static Future sendWebSmsCode({
|
|
||||||
int? cid,
|
|
||||||
required int tel,
|
|
||||||
required String token,
|
|
||||||
required String challenge,
|
|
||||||
required String validate,
|
|
||||||
required String seccode,
|
|
||||||
}) async {
|
|
||||||
Map data = {
|
|
||||||
'cid': cid,
|
|
||||||
'tel': tel,
|
|
||||||
'token': token,
|
|
||||||
'challenge': challenge,
|
|
||||||
'validate': validate,
|
|
||||||
'seccode': seccode,
|
|
||||||
};
|
|
||||||
FormData formData = FormData.fromMap({...data});
|
|
||||||
var res = await Request().post(
|
|
||||||
Api.smsCode,
|
|
||||||
data: formData,
|
|
||||||
options: Options(
|
|
||||||
contentType: Headers.formUrlEncodedContentType,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
print(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
// web端验证码登录
|
|
||||||
static Future loginInByWebSmsCode() async {}
|
|
||||||
|
|
||||||
// web端密码登录
|
|
||||||
static Future liginInByWebPwd() async {}
|
|
||||||
|
|
||||||
// app端验证码
|
|
||||||
static Future sendAppSmsCode({
|
|
||||||
int? cid,
|
|
||||||
required int tel,
|
|
||||||
required String token,
|
|
||||||
required String challenge,
|
|
||||||
required String validate,
|
|
||||||
required String seccode,
|
|
||||||
}) async {
|
|
||||||
Map<String, dynamic> data = {
|
|
||||||
'cid': cid,
|
|
||||||
'tel': tel,
|
|
||||||
'login_session_id': const Uuid().v4().replaceAll('-', ''),
|
|
||||||
'recaptcha_token': token,
|
|
||||||
'gee_challenge': challenge,
|
|
||||||
'gee_validate': validate,
|
|
||||||
'gee_seccode': seccode,
|
|
||||||
'channel': 'bili',
|
|
||||||
'buvid': buvid(),
|
|
||||||
'local_id': buvid(),
|
|
||||||
// 'ts': DateTime.now().millisecondsSinceEpoch ~/ 1000,
|
|
||||||
'statistics': {
|
|
||||||
"appId": 1,
|
|
||||||
"platform": 3,
|
|
||||||
"version": "7.52.0",
|
|
||||||
"abtest": ""
|
|
||||||
},
|
|
||||||
};
|
|
||||||
// FormData formData = FormData.fromMap({...data});
|
|
||||||
var res = await Request().post(
|
|
||||||
Api.appSmsCode,
|
|
||||||
data: data,
|
|
||||||
options: Options(
|
|
||||||
contentType: Headers.formUrlEncodedContentType,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
print(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
static String buvid() {
|
|
||||||
var mac = <String>[];
|
|
||||||
var random = Random();
|
|
||||||
|
|
||||||
for (var i = 0; i < 6; i++) {
|
|
||||||
var min = 0;
|
|
||||||
var max = 0xff;
|
|
||||||
var num = (random.nextInt(max - min + 1) + min).toRadixString(16);
|
|
||||||
mac.add(num);
|
|
||||||
}
|
|
||||||
|
|
||||||
var md5Str = md5.convert(utf8.encode(mac.join(':'))).toString();
|
|
||||||
var md5Arr = md5Str.split('');
|
|
||||||
return 'XY${md5Arr[2]}${md5Arr[12]}${md5Arr[22]}$md5Str';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取盐hash跟PubKey
|
|
||||||
static Future getWebKey() async {
|
|
||||||
var res = await Request().get(Api.getWebKey,
|
|
||||||
data: {'disable_rcmd': 0, 'local_id': LoginUtils.generateBuvid()});
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
return {'status': true, 'data': res.data['data']};
|
|
||||||
} else {
|
|
||||||
return {'status': false, 'data': {}, 'msg': res.data['message']};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// app端密码登录
|
|
||||||
static Future loginInByMobPwd({
|
|
||||||
required String tel,
|
|
||||||
required String password,
|
|
||||||
required String key,
|
|
||||||
required String rhash,
|
|
||||||
}) async {
|
|
||||||
dynamic publicKey = RSAKeyParser().parse(key);
|
|
||||||
String passwordEncryptyed =
|
|
||||||
Encrypter(RSA(publicKey: publicKey)).encrypt(rhash + password).base64;
|
|
||||||
Map<String, dynamic> data = {
|
|
||||||
'username': tel,
|
|
||||||
'password': passwordEncryptyed,
|
|
||||||
'local_id': LoginUtils.generateBuvid(),
|
|
||||||
'disable_rcmd': "0",
|
|
||||||
};
|
|
||||||
var res = await Request().post(
|
|
||||||
Api.loginInByPwdApi,
|
|
||||||
data: data,
|
|
||||||
options: Options(
|
|
||||||
contentType: Headers.formUrlEncodedContentType,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
print(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,16 +1,7 @@
|
|||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
|
||||||
import 'package:hive/hive.dart';
|
|
||||||
import 'package:pilipala/common/constants.dart';
|
|
||||||
import 'package:pilipala/http/index.dart';
|
import 'package:pilipala/http/index.dart';
|
||||||
import 'package:pilipala/models/dynamics/result.dart';
|
import 'package:pilipala/models/dynamics/result.dart';
|
||||||
import 'package:pilipala/models/follow/result.dart';
|
|
||||||
import 'package:pilipala/models/member/archive.dart';
|
import 'package:pilipala/models/member/archive.dart';
|
||||||
import 'package:pilipala/models/member/coin.dart';
|
|
||||||
import 'package:pilipala/models/member/info.dart';
|
import 'package:pilipala/models/member/info.dart';
|
||||||
import 'package:pilipala/models/member/seasons.dart';
|
|
||||||
import 'package:pilipala/models/member/tags.dart';
|
|
||||||
import 'package:pilipala/utils/storage.dart';
|
|
||||||
import 'package:pilipala/utils/utils.dart';
|
|
||||||
import 'package:pilipala/utils/wbi_sign.dart';
|
import 'package:pilipala/utils/wbi_sign.dart';
|
||||||
|
|
||||||
class MemberHttp {
|
class MemberHttp {
|
||||||
@ -27,7 +18,6 @@ class MemberHttp {
|
|||||||
var res = await Request().get(
|
var res = await Request().get(
|
||||||
Api.memberInfo,
|
Api.memberInfo,
|
||||||
data: params,
|
data: params,
|
||||||
extra: {'ua': 'pc'},
|
|
||||||
);
|
);
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
return {
|
return {
|
||||||
@ -93,7 +83,6 @@ class MemberHttp {
|
|||||||
var res = await Request().get(
|
var res = await Request().get(
|
||||||
Api.memberArchive,
|
Api.memberArchive,
|
||||||
data: params,
|
data: params,
|
||||||
extra: {'ua': 'pc'},
|
|
||||||
);
|
);
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
return {
|
return {
|
||||||
@ -153,312 +142,4 @@ class MemberHttp {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询分组
|
|
||||||
static Future followUpTags() async {
|
|
||||||
var res = await Request().get(Api.followUpTag);
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
return {
|
|
||||||
'status': true,
|
|
||||||
'data': res.data['data']
|
|
||||||
.map<MemberTagItemModel>((e) => MemberTagItemModel.fromJson(e))
|
|
||||||
.toList()
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
'status': false,
|
|
||||||
'data': [],
|
|
||||||
'msg': res.data['message'],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置分组
|
|
||||||
static Future addUsers(int? fids, String? tagids) async {
|
|
||||||
var res = await Request().post(Api.addUsers, queryParameters: {
|
|
||||||
'fids': fids,
|
|
||||||
'tagids': tagids ?? '0',
|
|
||||||
'csrf': await Request.getCsrf(),
|
|
||||||
}, data: {
|
|
||||||
'cross_domain': true
|
|
||||||
});
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
return {'status': true, 'data': [], 'msg': '操作成功'};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
'status': false,
|
|
||||||
'data': [],
|
|
||||||
'msg': res.data['message'],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取某分组下的up
|
|
||||||
static Future followUpGroup(
|
|
||||||
int? mid,
|
|
||||||
int? tagid,
|
|
||||||
int? pn,
|
|
||||||
int? ps,
|
|
||||||
) async {
|
|
||||||
var res = await Request().get(Api.followUpGroup, data: {
|
|
||||||
'mid': mid,
|
|
||||||
'tagid': tagid,
|
|
||||||
'pn': pn,
|
|
||||||
'ps': ps,
|
|
||||||
});
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
// FollowItemModel
|
|
||||||
return {
|
|
||||||
'status': true,
|
|
||||||
'data': res.data['data']
|
|
||||||
.map<FollowItemModel>((e) => FollowItemModel.fromJson(e))
|
|
||||||
.toList()
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
'status': false,
|
|
||||||
'data': [],
|
|
||||||
'msg': res.data['message'],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取up置顶
|
|
||||||
static Future getTopVideo(String? vmid) async {
|
|
||||||
var res = await Request().get(Api.getTopVideoApi);
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
return {
|
|
||||||
'status': true,
|
|
||||||
'data': res.data['data']
|
|
||||||
.map<MemberTagItemModel>((e) => MemberTagItemModel.fromJson(e))
|
|
||||||
.toList()
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
'status': false,
|
|
||||||
'data': [],
|
|
||||||
'msg': res.data['message'],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取uo专栏
|
|
||||||
static Future getMemberSeasons(int? mid, int? pn, int? ps) async {
|
|
||||||
var res = await Request().get(Api.getMemberSeasonsApi, data: {
|
|
||||||
'mid': mid,
|
|
||||||
'page_num': pn,
|
|
||||||
'page_size': ps,
|
|
||||||
});
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
return {
|
|
||||||
'status': true,
|
|
||||||
'data': MemberSeasonsDataModel.fromJson(res.data['data']['items_lists'])
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
'status': false,
|
|
||||||
'data': [],
|
|
||||||
'msg': res.data['message'],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 最近投币
|
|
||||||
static Future getRecentCoinVideo({required int mid}) async {
|
|
||||||
Map params = await WbiSign().makSign({
|
|
||||||
'mid': mid,
|
|
||||||
'gaia_source': 'main_web',
|
|
||||||
'web_location': 333.999,
|
|
||||||
});
|
|
||||||
var res = await Request().get(
|
|
||||||
Api.getRecentCoinVideoApi,
|
|
||||||
data: {
|
|
||||||
'vmid': mid,
|
|
||||||
'gaia_source': 'main_web',
|
|
||||||
'web_location': 333.999,
|
|
||||||
'w_rid': params['w_rid'],
|
|
||||||
'wts': params['wts'],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
return {
|
|
||||||
'status': true,
|
|
||||||
'data': res.data['data']
|
|
||||||
.map<MemberCoinsDataModel>((e) => MemberCoinsDataModel.fromJson(e))
|
|
||||||
.toList(),
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
'status': false,
|
|
||||||
'data': [],
|
|
||||||
'msg': res.data['message'],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 最近点赞
|
|
||||||
static Future getRecentLikeVideo({required int mid}) async {
|
|
||||||
Map params = await WbiSign().makSign({
|
|
||||||
'mid': mid,
|
|
||||||
'gaia_source': 'main_web',
|
|
||||||
'web_location': 333.999,
|
|
||||||
});
|
|
||||||
var res = await Request().get(
|
|
||||||
Api.getRecentLikeVideoApi,
|
|
||||||
data: {
|
|
||||||
'vmid': mid,
|
|
||||||
'gaia_source': 'main_web',
|
|
||||||
'web_location': 333.999,
|
|
||||||
'w_rid': params['w_rid'],
|
|
||||||
'wts': params['wts'],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
return {
|
|
||||||
'status': true,
|
|
||||||
'data': MemberSeasonsDataModel.fromJson(res.data['data']['items_lists'])
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
'status': false,
|
|
||||||
'data': [],
|
|
||||||
'msg': res.data['message'],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查看某个专栏
|
|
||||||
static Future getSeasonDetail({
|
|
||||||
required int mid,
|
|
||||||
required int seasonId,
|
|
||||||
bool sortReverse = false,
|
|
||||||
required int pn,
|
|
||||||
required int ps,
|
|
||||||
}) async {
|
|
||||||
var res = await Request().get(
|
|
||||||
Api.getSeasonDetailApi,
|
|
||||||
data: {
|
|
||||||
'mid': mid,
|
|
||||||
'season_id': seasonId,
|
|
||||||
'sort_reverse': sortReverse,
|
|
||||||
'page_num': pn,
|
|
||||||
'page_size': ps,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
try {
|
|
||||||
return {
|
|
||||||
'status': true,
|
|
||||||
'data': MemberSeasonsList.fromJson(res.data['data'])
|
|
||||||
};
|
|
||||||
} catch (err) {
|
|
||||||
print(err);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
'status': false,
|
|
||||||
'data': [],
|
|
||||||
'msg': res.data['message'],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取TV authCode
|
|
||||||
static Future getTVCode() async {
|
|
||||||
SmartDialog.showLoading();
|
|
||||||
var params = {
|
|
||||||
'appkey': Constants.appKey,
|
|
||||||
'local_id': '0',
|
|
||||||
'ts': (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(),
|
|
||||||
};
|
|
||||||
String sign = Utils.appSign(
|
|
||||||
params,
|
|
||||||
Constants.appKey,
|
|
||||||
Constants.appSec,
|
|
||||||
);
|
|
||||||
var res = await Request()
|
|
||||||
.post(Api.getTVCode, queryParameters: {...params, 'sign': sign});
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
return {
|
|
||||||
'status': true,
|
|
||||||
'data': res.data['data']['auth_code'],
|
|
||||||
'msg': '操作成功'
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
'status': false,
|
|
||||||
'data': [],
|
|
||||||
'msg': res.data['message'],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取access_key
|
|
||||||
static Future cookieToKey() async {
|
|
||||||
var authCodeRes = await getTVCode();
|
|
||||||
if (authCodeRes['status']) {
|
|
||||||
var res = await Request().post(Api.cookieToKey, queryParameters: {
|
|
||||||
'auth_code': authCodeRes['data'],
|
|
||||||
'build': 708200,
|
|
||||||
'csrf': await Request.getCsrf(),
|
|
||||||
});
|
|
||||||
await Future.delayed(const Duration(milliseconds: 300));
|
|
||||||
await qrcodePoll(authCodeRes['data']);
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
return {'status': true, 'data': [], 'msg': '操作成功'};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
'status': false,
|
|
||||||
'data': [],
|
|
||||||
'msg': res.data['message'],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future qrcodePoll(authCode) async {
|
|
||||||
var params = {
|
|
||||||
'appkey': Constants.appKey,
|
|
||||||
'auth_code': authCode.toString(),
|
|
||||||
'local_id': '0',
|
|
||||||
'ts': (DateTime.now().millisecondsSinceEpoch ~/ 1000).toString(),
|
|
||||||
};
|
|
||||||
String sign = Utils.appSign(
|
|
||||||
params,
|
|
||||||
Constants.appKey,
|
|
||||||
Constants.appSec,
|
|
||||||
);
|
|
||||||
var res = await Request()
|
|
||||||
.post(Api.qrcodePoll, queryParameters: {...params, 'sign': sign});
|
|
||||||
SmartDialog.dismiss();
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
String accessKey = res.data['data']['access_token'];
|
|
||||||
Box localCache = GStrorage.localCache;
|
|
||||||
Box userInfoCache = GStrorage.userInfo;
|
|
||||||
var userInfo = userInfoCache.get('userInfoCache');
|
|
||||||
localCache.put(
|
|
||||||
LocalCacheKey.accessKey, {'mid': userInfo.mid, 'value': accessKey});
|
|
||||||
return {'status': true, 'data': [], 'msg': '操作成功'};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
'status': false,
|
|
||||||
'data': [],
|
|
||||||
'msg': res.data['message'],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取up播放数、点赞数
|
|
||||||
static Future memberView({required int mid}) async {
|
|
||||||
var res = await Request().get(Api.getMemberViewApi, data: {'mid': mid});
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
return {'status': true, 'data': res.data['data']};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
'status': false,
|
|
||||||
'data': [],
|
|
||||||
'msg': res.data['message'],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,89 +0,0 @@
|
|||||||
import 'package:pilipala/http/api.dart';
|
|
||||||
import 'package:pilipala/http/init.dart';
|
|
||||||
import 'package:pilipala/models/msg/account.dart';
|
|
||||||
import 'package:pilipala/models/msg/session.dart';
|
|
||||||
import 'package:pilipala/utils/wbi_sign.dart';
|
|
||||||
|
|
||||||
class MsgHttp {
|
|
||||||
// 会话列表
|
|
||||||
static Future sessionList({int? endTs}) async {
|
|
||||||
Map<String, dynamic> params = {
|
|
||||||
'session_type': 1,
|
|
||||||
'group_fold': 1,
|
|
||||||
'unfollow_fold': 0,
|
|
||||||
'sort_rule': 2,
|
|
||||||
'build': 0,
|
|
||||||
'mobi_app': 'web',
|
|
||||||
};
|
|
||||||
if (endTs != null) {
|
|
||||||
params['end_ts'] = endTs;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map signParams = await WbiSign().makSign(params);
|
|
||||||
var res = await Request().get(Api.sessionList, data: signParams);
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
return {
|
|
||||||
'status': true,
|
|
||||||
'data': SessionDataModel.fromJson(res.data['data']),
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
'status': false,
|
|
||||||
'date': [],
|
|
||||||
'msg': res.data['message'],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future accountList(uids) async {
|
|
||||||
var res = await Request().get(Api.sessionAccountList, data: {
|
|
||||||
'uids': uids,
|
|
||||||
'build': 0,
|
|
||||||
'mobi_app': 'web',
|
|
||||||
});
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
return {
|
|
||||||
'status': true,
|
|
||||||
'data': res.data['data']
|
|
||||||
.map<AccountListModel>((e) => AccountListModel.fromJson(e))
|
|
||||||
.toList(),
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
'status': false,
|
|
||||||
'date': [],
|
|
||||||
'msg': res.data['message'],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future sessionMsg({
|
|
||||||
int? talkerId,
|
|
||||||
}) async {
|
|
||||||
Map params = await WbiSign().makSign({
|
|
||||||
'talker_id': talkerId,
|
|
||||||
'session_type': 1,
|
|
||||||
'size': 20,
|
|
||||||
'sender_device_id': 1,
|
|
||||||
'build': 0,
|
|
||||||
'mobi_app': 'web',
|
|
||||||
});
|
|
||||||
var res = await Request().get(Api.sessionMsg, data: params);
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
try {
|
|
||||||
return {
|
|
||||||
'status': true,
|
|
||||||
'data': SessionMsgDataModel.fromJson(res.data['data']),
|
|
||||||
};
|
|
||||||
} catch (err) {
|
|
||||||
print(err);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
'status': false,
|
|
||||||
'date': [],
|
|
||||||
'msg': res.data['message'],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -26,7 +26,7 @@ class ReplyHttp {
|
|||||||
Map errMap = {
|
Map errMap = {
|
||||||
-400: '请求错误',
|
-400: '请求错误',
|
||||||
-404: '无此项',
|
-404: '无此项',
|
||||||
12002: '当前页面评论功能已关闭',
|
12002: '当前页面评论功能已关闭"',
|
||||||
12009: '评论主体的type不合法',
|
12009: '评论主体的type不合法',
|
||||||
12061: 'UP主已关闭评论区',
|
12061: 'UP主已关闭评论区',
|
||||||
};
|
};
|
||||||
|
|||||||
@ -8,7 +8,6 @@ import 'package:pilipala/models/user/fav_folder.dart';
|
|||||||
import 'package:pilipala/models/user/history.dart';
|
import 'package:pilipala/models/user/history.dart';
|
||||||
import 'package:pilipala/models/user/info.dart';
|
import 'package:pilipala/models/user/info.dart';
|
||||||
import 'package:pilipala/models/user/stat.dart';
|
import 'package:pilipala/models/user/stat.dart';
|
||||||
import 'package:pilipala/utils/wbi_sign.dart';
|
|
||||||
|
|
||||||
class UserHttp {
|
class UserHttp {
|
||||||
static Future<dynamic> userStat({required int mid}) async {
|
static Future<dynamic> userStat({required int mid}) async {
|
||||||
@ -71,15 +70,14 @@ class UserHttp {
|
|||||||
required int pn,
|
required int pn,
|
||||||
required int ps,
|
required int ps,
|
||||||
String keyword = '',
|
String keyword = '',
|
||||||
String order = 'mtime',
|
String order = 'mtime'}) async {
|
||||||
int type = 0}) async {
|
|
||||||
var res = await Request().get(Api.userFavFolderDetail, data: {
|
var res = await Request().get(Api.userFavFolderDetail, data: {
|
||||||
'media_id': mediaId,
|
'media_id': mediaId,
|
||||||
'pn': pn,
|
'pn': pn,
|
||||||
'ps': ps,
|
'ps': ps,
|
||||||
'keyword': keyword,
|
'keyword': keyword,
|
||||||
'order': order,
|
'order': order,
|
||||||
'type': type,
|
'type': 0,
|
||||||
'tid': 0,
|
'tid': 0,
|
||||||
'platform': 'web'
|
'platform': 'web'
|
||||||
});
|
});
|
||||||
@ -199,7 +197,7 @@ class UserHttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取用户凭证 失效
|
// 获取用户凭证
|
||||||
static Future thirdLogin() async {
|
static Future thirdLogin() async {
|
||||||
var res = await Request().get(
|
var res = await Request().get(
|
||||||
'https://passport.bilibili.com/login/app/third',
|
'https://passport.bilibili.com/login/app/third',
|
||||||
@ -251,44 +249,6 @@ class UserHttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future hasFollow(int mid) async {
|
|
||||||
var res = await Request().get(
|
|
||||||
Api.hasFollow,
|
|
||||||
data: {
|
|
||||||
'fid': mid,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
return {'status': true, 'data': res.data['data']};
|
|
||||||
} else {
|
|
||||||
return {'status': false, 'msg': res.data['message']};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// // 相互关系查询
|
|
||||||
// static Future relationSearch(int mid) async {
|
|
||||||
// Map params = await WbiSign().makSign({
|
|
||||||
// 'mid': mid,
|
|
||||||
// 'token': '',
|
|
||||||
// 'platform': 'web',
|
|
||||||
// 'web_location': 1550101,
|
|
||||||
// });
|
|
||||||
// var res = await Request().get(
|
|
||||||
// Api.relationSearch,
|
|
||||||
// data: {
|
|
||||||
// 'mid': mid,
|
|
||||||
// 'w_rid': params['w_rid'],
|
|
||||||
// 'wts': params['wts'],
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
// if (res.data['code'] == 0) {
|
|
||||||
// // relation 主动状态
|
|
||||||
// // 被动状态
|
|
||||||
// return {'status': true, 'data': res.data['data']};
|
|
||||||
// } else {
|
|
||||||
// return {'status': false, 'msg': res.data['message']};
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 搜索历史记录
|
// 搜索历史记录
|
||||||
static Future searchHistory(
|
static Future searchHistory(
|
||||||
{required int pn, required String keyword}) async {
|
{required int pn, required String keyword}) async {
|
||||||
|
|||||||
@ -9,11 +9,9 @@ import 'package:pilipala/models/home/rcmd/result.dart';
|
|||||||
import 'package:pilipala/models/model_hot_video_item.dart';
|
import 'package:pilipala/models/model_hot_video_item.dart';
|
||||||
import 'package:pilipala/models/model_rec_video_item.dart';
|
import 'package:pilipala/models/model_rec_video_item.dart';
|
||||||
import 'package:pilipala/models/user/fav_folder.dart';
|
import 'package:pilipala/models/user/fav_folder.dart';
|
||||||
import 'package:pilipala/models/video/ai.dart';
|
|
||||||
import 'package:pilipala/models/video/play/url.dart';
|
import 'package:pilipala/models/video/play/url.dart';
|
||||||
import 'package:pilipala/models/video_detail_res.dart';
|
import 'package:pilipala/models/video_detail_res.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
import 'package:pilipala/utils/wbi_sign.dart';
|
|
||||||
|
|
||||||
/// res.data['code'] == 0 请求正常返回结果
|
/// res.data['code'] == 0 请求正常返回结果
|
||||||
/// res.data['data'] 为结果
|
/// res.data['data'] 为结果
|
||||||
@ -24,7 +22,6 @@ class VideoHttp {
|
|||||||
static Box setting = GStrorage.setting;
|
static Box setting = GStrorage.setting;
|
||||||
static bool enableRcmdDynamic =
|
static bool enableRcmdDynamic =
|
||||||
setting.get(SettingBoxKey.enableRcmdDynamic, defaultValue: true);
|
setting.get(SettingBoxKey.enableRcmdDynamic, defaultValue: true);
|
||||||
static Box userInfoCache = GStrorage.userInfo;
|
|
||||||
|
|
||||||
// 首页推荐视频
|
// 首页推荐视频
|
||||||
static Future rcmdVideoList({required int ps, required int freshIdx}) async {
|
static Future rcmdVideoList({required int ps, required int freshIdx}) async {
|
||||||
@ -136,11 +133,6 @@ class VideoHttp {
|
|||||||
// 'platform': '',
|
// 'platform': '',
|
||||||
// 'high_quality': ''
|
// 'high_quality': ''
|
||||||
};
|
};
|
||||||
// 免登录查看1080p
|
|
||||||
if (userInfoCache.get('userInfoCache') == null &&
|
|
||||||
setting.get(SettingBoxKey.p1080, defaultValue: true)) {
|
|
||||||
data['try_look'] = 1;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
var res = await Request().get(Api.videoUrl, data: data);
|
var res = await Request().get(Api.videoUrl, data: data);
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
@ -422,23 +414,4 @@ class VideoHttp {
|
|||||||
return {'status': true, 'data': res.data['data']};
|
return {'status': true, 'data': res.data['data']};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future aiConclusion({
|
|
||||||
String? bvid,
|
|
||||||
int? cid,
|
|
||||||
int? upMid,
|
|
||||||
}) async {
|
|
||||||
Map params = await WbiSign().makSign({
|
|
||||||
'bvid': bvid,
|
|
||||||
'cid': cid,
|
|
||||||
'up_mid': upMid,
|
|
||||||
});
|
|
||||||
var res = await Request().get(Api.aiConclusion, data: params);
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
return {
|
|
||||||
'status': true,
|
|
||||||
'data': AiConclusionModel.fromJson(res.data['data']),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,4 @@
|
|||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_displaymode/flutter_displaymode.dart';
|
|
||||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
import 'package:flutter_localizations/flutter_localizations.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';
|
||||||
@ -16,7 +13,6 @@ import 'package:pilipala/pages/search/index.dart';
|
|||||||
import 'package:pilipala/pages/video/detail/index.dart';
|
import 'package:pilipala/pages/video/detail/index.dart';
|
||||||
import 'package:pilipala/router/app_pages.dart';
|
import 'package:pilipala/router/app_pages.dart';
|
||||||
import 'package:pilipala/pages/main/view.dart';
|
import 'package:pilipala/pages/main/view.dart';
|
||||||
import 'package:pilipala/services/service_locator.dart';
|
|
||||||
import 'package:pilipala/utils/app_scheme.dart';
|
import 'package:pilipala/utils/app_scheme.dart';
|
||||||
import 'package:pilipala/utils/data.dart';
|
import 'package:pilipala/utils/data.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
@ -29,7 +25,6 @@ void main() async {
|
|||||||
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown])
|
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown])
|
||||||
.then((_) async {
|
.then((_) async {
|
||||||
await GStrorage.init();
|
await GStrorage.init();
|
||||||
await setupServiceLocator();
|
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
// 小白条、导航栏沉浸
|
// 小白条、导航栏沉浸
|
||||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
|
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
|
||||||
@ -66,23 +61,6 @@ class MyApp extends StatelessWidget {
|
|||||||
double textScale =
|
double textScale =
|
||||||
setting.get(SettingBoxKey.defaultTextScale, defaultValue: 1.0);
|
setting.get(SettingBoxKey.defaultTextScale, defaultValue: 1.0);
|
||||||
|
|
||||||
// 强制设置高帧率
|
|
||||||
if (Platform.isAndroid) {
|
|
||||||
try {
|
|
||||||
late List modes;
|
|
||||||
FlutterDisplayMode.supported.then((value) {
|
|
||||||
modes = value;
|
|
||||||
var storageDisplay = setting.get(SettingBoxKey.displayMode);
|
|
||||||
DisplayMode f = DisplayMode.auto;
|
|
||||||
if (storageDisplay != null) {
|
|
||||||
f = modes.firstWhere((e) => e.toString() == storageDisplay);
|
|
||||||
}
|
|
||||||
DisplayMode preferred = modes.toList().firstWhere((el) => el == f);
|
|
||||||
FlutterDisplayMode.setPreferredMode(preferred);
|
|
||||||
});
|
|
||||||
} catch (_) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
return DynamicColorBuilder(
|
return DynamicColorBuilder(
|
||||||
builder: ((ColorScheme? lightDynamic, ColorScheme? darkDynamic) {
|
builder: ((ColorScheme? lightDynamic, ColorScheme? darkDynamic) {
|
||||||
ColorScheme? lightColorScheme;
|
ColorScheme? lightColorScheme;
|
||||||
|
|||||||
@ -244,9 +244,7 @@ class Vote {
|
|||||||
choiceCnt = json['choice_cnt'];
|
choiceCnt = json['choice_cnt'];
|
||||||
share = json['share'];
|
share = json['share'];
|
||||||
defaultShare = json['default_share'];
|
defaultShare = json['default_share'];
|
||||||
endTime = json['end_time'] is int
|
endTime = json['end_time'];
|
||||||
? json['end_time']
|
|
||||||
: int.parse(json['end_time']);
|
|
||||||
joinNum = json['join_num'];
|
joinNum = json['join_num'];
|
||||||
status = json['status'];
|
status = json['status'];
|
||||||
type = json['type'];
|
type = json['type'];
|
||||||
|
|||||||
@ -8,7 +8,7 @@ class FollowDataModel {
|
|||||||
List<FollowItemModel>? list;
|
List<FollowItemModel>? list;
|
||||||
|
|
||||||
FollowDataModel.fromJson(Map<String, dynamic> json) {
|
FollowDataModel.fromJson(Map<String, dynamic> json) {
|
||||||
total = json['total'] ?? 0;
|
total = json['total'];
|
||||||
list = json['list']
|
list = json['list']
|
||||||
.map<FollowItemModel>((e) => FollowItemModel.fromJson(e))
|
.map<FollowItemModel>((e) => FollowItemModel.fromJson(e))
|
||||||
.toList();
|
.toList();
|
||||||
@ -19,7 +19,7 @@ class FollowItemModel {
|
|||||||
FollowItemModel({
|
FollowItemModel({
|
||||||
this.mid,
|
this.mid,
|
||||||
this.attribute,
|
this.attribute,
|
||||||
// this.mtime,
|
this.mtime,
|
||||||
this.tag,
|
this.tag,
|
||||||
this.special,
|
this.special,
|
||||||
this.uname,
|
this.uname,
|
||||||
@ -30,7 +30,7 @@ class FollowItemModel {
|
|||||||
|
|
||||||
int? mid;
|
int? mid;
|
||||||
int? attribute;
|
int? attribute;
|
||||||
// int? mtime;
|
int? mtime;
|
||||||
List? tag;
|
List? tag;
|
||||||
int? special;
|
int? special;
|
||||||
String? uname;
|
String? uname;
|
||||||
@ -41,7 +41,7 @@ class FollowItemModel {
|
|||||||
FollowItemModel.fromJson(Map<String, dynamic> json) {
|
FollowItemModel.fromJson(Map<String, dynamic> json) {
|
||||||
mid = json['mid'];
|
mid = json['mid'];
|
||||||
attribute = json['attribute'];
|
attribute = json['attribute'];
|
||||||
// mtime = json['mtime'];
|
mtime = json['mtime'];
|
||||||
tag = json['tag'];
|
tag = json['tag'];
|
||||||
special = json['special'];
|
special = json['special'];
|
||||||
uname = json['uname'];
|
uname = json['uname'];
|
||||||
|
|||||||
@ -118,7 +118,7 @@ class RcmdStat {
|
|||||||
|
|
||||||
RcmdStat.fromJson(Map<String, dynamic> json) {
|
RcmdStat.fromJson(Map<String, dynamic> json) {
|
||||||
view = json["cover_left_text_1"];
|
view = json["cover_left_text_1"];
|
||||||
danmu = json['cover_left_text_2'] ?? '-';
|
danmu = json['cover_left_text_2'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,49 +0,0 @@
|
|||||||
class CaptchaDataModel {
|
|
||||||
CaptchaDataModel({
|
|
||||||
this.type,
|
|
||||||
this.token,
|
|
||||||
this.geetest,
|
|
||||||
this.tencent,
|
|
||||||
this.validate,
|
|
||||||
this.seccode,
|
|
||||||
});
|
|
||||||
|
|
||||||
String? type;
|
|
||||||
String? token;
|
|
||||||
GeetestData? geetest;
|
|
||||||
Tencent? tencent;
|
|
||||||
String? validate;
|
|
||||||
String? seccode;
|
|
||||||
|
|
||||||
CaptchaDataModel.fromJson(Map<String, dynamic> json) {
|
|
||||||
type = json["type"];
|
|
||||||
token = json["token"];
|
|
||||||
geetest =
|
|
||||||
json["geetest"] != null ? GeetestData.fromJson(json["geetest"]) : null;
|
|
||||||
tencent =
|
|
||||||
json["tencent"] != null ? Tencent.fromJson(json["tencent"]) : null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GeetestData {
|
|
||||||
GeetestData({
|
|
||||||
this.challenge,
|
|
||||||
this.gt,
|
|
||||||
});
|
|
||||||
|
|
||||||
String? challenge;
|
|
||||||
String? gt;
|
|
||||||
|
|
||||||
GeetestData.fromJson(Map<String, dynamic> json) {
|
|
||||||
challenge = json["challenge"];
|
|
||||||
gt = json["gt"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Tencent {
|
|
||||||
Tencent({this.appid});
|
|
||||||
String? appid;
|
|
||||||
Tencent.fromJson(Map<String, dynamic> json) {
|
|
||||||
appid = json["appid"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,89 +0,0 @@
|
|||||||
class MemberCoinsDataModel {
|
|
||||||
MemberCoinsDataModel({
|
|
||||||
this.aid,
|
|
||||||
this.bvid,
|
|
||||||
this.cid,
|
|
||||||
this.coins,
|
|
||||||
this.copyright,
|
|
||||||
this.ctime,
|
|
||||||
this.desc,
|
|
||||||
this.duration,
|
|
||||||
this.owner,
|
|
||||||
this.pic,
|
|
||||||
this.pubLocation,
|
|
||||||
this.pubdate,
|
|
||||||
this.resourceType,
|
|
||||||
this.state,
|
|
||||||
this.subtitle,
|
|
||||||
this.time,
|
|
||||||
this.title,
|
|
||||||
this.tname,
|
|
||||||
this.videos,
|
|
||||||
this.view,
|
|
||||||
this.danmaku,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? aid;
|
|
||||||
String? bvid;
|
|
||||||
int? cid;
|
|
||||||
int? coins;
|
|
||||||
int? copyright;
|
|
||||||
int? ctime;
|
|
||||||
String? desc;
|
|
||||||
int? duration;
|
|
||||||
Owner? owner;
|
|
||||||
String? pic;
|
|
||||||
String? pubLocation;
|
|
||||||
int? pubdate;
|
|
||||||
String? resourceType;
|
|
||||||
int? state;
|
|
||||||
String? subtitle;
|
|
||||||
int? time;
|
|
||||||
String? title;
|
|
||||||
String? tname;
|
|
||||||
int? videos;
|
|
||||||
int? view;
|
|
||||||
int? danmaku;
|
|
||||||
|
|
||||||
MemberCoinsDataModel.fromJson(Map<String, dynamic> json) {
|
|
||||||
aid = json['aid'];
|
|
||||||
bvid = json['bvid'];
|
|
||||||
cid = json['cid'];
|
|
||||||
coins = json['coins'];
|
|
||||||
copyright = json['copyright'];
|
|
||||||
ctime = json['ctime'];
|
|
||||||
desc = json['desc'];
|
|
||||||
duration = json['duration'];
|
|
||||||
owner = Owner.fromJson(json['owner']);
|
|
||||||
pic = json['pic'];
|
|
||||||
pubLocation = json['pub_location'];
|
|
||||||
pubdate = json['pubdate'];
|
|
||||||
resourceType = json['resource_type'];
|
|
||||||
state = json['state'];
|
|
||||||
subtitle = json['subtitle'];
|
|
||||||
time = json['time'];
|
|
||||||
title = json['title'];
|
|
||||||
tname = json['tname'];
|
|
||||||
videos = json['videos'];
|
|
||||||
view = json['stat']['view'];
|
|
||||||
danmaku = json['stat']['danmaku'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Owner {
|
|
||||||
Owner({
|
|
||||||
this.mid,
|
|
||||||
this.name,
|
|
||||||
this.face,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? mid;
|
|
||||||
String? name;
|
|
||||||
String? face;
|
|
||||||
|
|
||||||
Owner.fromJson(Map<String, dynamic> json) {
|
|
||||||
mid = json['mid'];
|
|
||||||
name = json['name'];
|
|
||||||
face = json['face'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,108 +0,0 @@
|
|||||||
class MemberSeasonsDataModel {
|
|
||||||
MemberSeasonsDataModel({
|
|
||||||
this.page,
|
|
||||||
this.seasonsList,
|
|
||||||
});
|
|
||||||
|
|
||||||
Map? page;
|
|
||||||
List<MemberSeasonsList>? seasonsList;
|
|
||||||
|
|
||||||
MemberSeasonsDataModel.fromJson(Map<String, dynamic> json) {
|
|
||||||
page = json['page'];
|
|
||||||
seasonsList = json['seasons_list'] != null
|
|
||||||
? json['seasons_list']
|
|
||||||
.map<MemberSeasonsList>((e) => MemberSeasonsList.fromJson(e))
|
|
||||||
.toList()
|
|
||||||
: [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MemberSeasonsList {
|
|
||||||
MemberSeasonsList({
|
|
||||||
this.archives,
|
|
||||||
this.meta,
|
|
||||||
this.recentAids,
|
|
||||||
this.page,
|
|
||||||
});
|
|
||||||
|
|
||||||
List<MemberArchiveItem>? archives;
|
|
||||||
MamberMeta? meta;
|
|
||||||
List? recentAids;
|
|
||||||
Map? page;
|
|
||||||
|
|
||||||
MemberSeasonsList.fromJson(Map<String, dynamic> json) {
|
|
||||||
archives = json['archives'] != null
|
|
||||||
? json['archives']
|
|
||||||
.map<MemberArchiveItem>((e) => MemberArchiveItem.fromJson(e))
|
|
||||||
.toList()
|
|
||||||
: [];
|
|
||||||
meta = MamberMeta.fromJson(json['meta']);
|
|
||||||
page = json['page'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MemberArchiveItem {
|
|
||||||
MemberArchiveItem({
|
|
||||||
this.aid,
|
|
||||||
this.bvid,
|
|
||||||
this.ctime,
|
|
||||||
this.duration,
|
|
||||||
this.pic,
|
|
||||||
this.cover,
|
|
||||||
this.pubdate,
|
|
||||||
this.view,
|
|
||||||
this.title,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? aid;
|
|
||||||
String? bvid;
|
|
||||||
int? ctime;
|
|
||||||
int? duration;
|
|
||||||
String? pic;
|
|
||||||
String? cover;
|
|
||||||
int? pubdate;
|
|
||||||
int? view;
|
|
||||||
String? title;
|
|
||||||
|
|
||||||
MemberArchiveItem.fromJson(Map<String, dynamic> json) {
|
|
||||||
aid = json['aid'];
|
|
||||||
bvid = json['bvid'];
|
|
||||||
ctime = json['ctime'];
|
|
||||||
duration = json['duration'];
|
|
||||||
pic = json['pic'];
|
|
||||||
cover = json['pic'];
|
|
||||||
pubdate = json['pubdate'];
|
|
||||||
view = json['stat']['view'];
|
|
||||||
title = json['title'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MamberMeta {
|
|
||||||
MamberMeta({
|
|
||||||
this.cover,
|
|
||||||
this.description,
|
|
||||||
this.mid,
|
|
||||||
this.name,
|
|
||||||
this.ptime,
|
|
||||||
this.seasonId,
|
|
||||||
this.total,
|
|
||||||
});
|
|
||||||
|
|
||||||
String? cover;
|
|
||||||
String? description;
|
|
||||||
int? mid;
|
|
||||||
String? name;
|
|
||||||
int? ptime;
|
|
||||||
int? seasonId;
|
|
||||||
int? total;
|
|
||||||
|
|
||||||
MamberMeta.fromJson(Map<String, dynamic> json) {
|
|
||||||
cover = json['cover'];
|
|
||||||
description = json['description'];
|
|
||||||
mid = json['mid'];
|
|
||||||
name = json['name'];
|
|
||||||
ptime = json['ptime'];
|
|
||||||
seasonId = json['season_id'];
|
|
||||||
total = json['total'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
class MemberTagItemModel {
|
|
||||||
MemberTagItemModel({
|
|
||||||
this.count,
|
|
||||||
this.name,
|
|
||||||
this.tagid,
|
|
||||||
this.tip,
|
|
||||||
this.checked,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? count;
|
|
||||||
String? name;
|
|
||||||
int? tagid;
|
|
||||||
String? tip;
|
|
||||||
bool? checked;
|
|
||||||
|
|
||||||
MemberTagItemModel.fromJson(Map<String, dynamic> json) {
|
|
||||||
count = json['count'];
|
|
||||||
name = json['name'];
|
|
||||||
tagid = json['tagid'];
|
|
||||||
tip = json['tip'];
|
|
||||||
checked = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -36,7 +36,7 @@ class RecVideoItemModel {
|
|||||||
@HiveField(6)
|
@HiveField(6)
|
||||||
String? title = '';
|
String? title = '';
|
||||||
@HiveField(7)
|
@HiveField(7)
|
||||||
String? duration = '';
|
int? duration = -1;
|
||||||
@HiveField(8)
|
@HiveField(8)
|
||||||
int? pubdate = -1;
|
int? pubdate = -1;
|
||||||
@HiveField(9)
|
@HiveField(9)
|
||||||
@ -56,7 +56,7 @@ class RecVideoItemModel {
|
|||||||
uri = json["uri"];
|
uri = json["uri"];
|
||||||
pic = json["pic"];
|
pic = json["pic"];
|
||||||
title = json["title"];
|
title = json["title"];
|
||||||
duration = json["duration"].toString();
|
duration = json["duration"];
|
||||||
pubdate = json["pubdate"];
|
pubdate = json["pubdate"];
|
||||||
owner = Owner.fromJson(json["owner"]);
|
owner = Owner.fromJson(json["owner"]);
|
||||||
stat = Stat.fromJson(json["stat"]);
|
stat = Stat.fromJson(json["stat"]);
|
||||||
@ -72,19 +72,19 @@ class Stat {
|
|||||||
Stat({
|
Stat({
|
||||||
this.view,
|
this.view,
|
||||||
this.like,
|
this.like,
|
||||||
this.danmu,
|
this.danmaku,
|
||||||
});
|
});
|
||||||
@HiveField(0)
|
@HiveField(0)
|
||||||
int? view;
|
int? view;
|
||||||
@HiveField(1)
|
@HiveField(1)
|
||||||
int? like;
|
int? like;
|
||||||
@HiveField(2)
|
@HiveField(2)
|
||||||
int? danmu;
|
int? danmaku;
|
||||||
|
|
||||||
Stat.fromJson(Map<String, dynamic> json) {
|
Stat.fromJson(Map<String, dynamic> json) {
|
||||||
view = json["view"];
|
view = json["view"];
|
||||||
like = json["like"];
|
like = json["like"];
|
||||||
danmu = json['danmaku'];
|
danmaku = json['danmaku'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -24,7 +24,7 @@ class RecVideoItemModelAdapter extends TypeAdapter<RecVideoItemModel> {
|
|||||||
uri: fields[4] as String?,
|
uri: fields[4] as String?,
|
||||||
pic: fields[5] as String?,
|
pic: fields[5] as String?,
|
||||||
title: fields[6] as String?,
|
title: fields[6] as String?,
|
||||||
duration: fields[7] as String?,
|
duration: fields[7] as int?,
|
||||||
pubdate: fields[8] as int?,
|
pubdate: fields[8] as int?,
|
||||||
owner: fields[9] as Owner?,
|
owner: fields[9] as Owner?,
|
||||||
stat: fields[10] as Stat?,
|
stat: fields[10] as Stat?,
|
||||||
@ -89,7 +89,7 @@ class StatAdapter extends TypeAdapter<Stat> {
|
|||||||
return Stat(
|
return Stat(
|
||||||
view: fields[0] as int?,
|
view: fields[0] as int?,
|
||||||
like: fields[1] as int?,
|
like: fields[1] as int?,
|
||||||
danmu: fields[2] as int?,
|
danmaku: fields[2] as int?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ class StatAdapter extends TypeAdapter<Stat> {
|
|||||||
..writeByte(1)
|
..writeByte(1)
|
||||||
..write(obj.like)
|
..write(obj.like)
|
||||||
..writeByte(2)
|
..writeByte(2)
|
||||||
..write(obj.danmu);
|
..write(obj.danmaku);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@ -1,80 +0,0 @@
|
|||||||
class AccountListModel {
|
|
||||||
AccountListModel({
|
|
||||||
this.mid,
|
|
||||||
this.name,
|
|
||||||
this.sex,
|
|
||||||
this.face,
|
|
||||||
this.sign,
|
|
||||||
this.rank,
|
|
||||||
this.level,
|
|
||||||
this.silence,
|
|
||||||
this.vip,
|
|
||||||
this.pendant,
|
|
||||||
this.nameplate,
|
|
||||||
this.official,
|
|
||||||
this.birthday,
|
|
||||||
this.isFakeAccount,
|
|
||||||
this.isDeleted,
|
|
||||||
this.inRegAudit,
|
|
||||||
this.faceNft,
|
|
||||||
this.faceNftNew,
|
|
||||||
this.isSeniorMember,
|
|
||||||
this.digitalId,
|
|
||||||
this.digitalType,
|
|
||||||
this.attestation,
|
|
||||||
this.expertInfo,
|
|
||||||
this.honours,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? mid;
|
|
||||||
String? name;
|
|
||||||
String? sex;
|
|
||||||
String? face;
|
|
||||||
String? sign;
|
|
||||||
int? rank;
|
|
||||||
int? level;
|
|
||||||
int? silence;
|
|
||||||
Map? vip;
|
|
||||||
Map? pendant;
|
|
||||||
Map? nameplate;
|
|
||||||
Map? official;
|
|
||||||
int? birthday;
|
|
||||||
int? isFakeAccount;
|
|
||||||
int? isDeleted;
|
|
||||||
int? inRegAudit;
|
|
||||||
int? faceNft;
|
|
||||||
int? faceNftNew;
|
|
||||||
int? isSeniorMember;
|
|
||||||
String? digitalId;
|
|
||||||
int? digitalType;
|
|
||||||
Map? attestation;
|
|
||||||
Map? expertInfo;
|
|
||||||
Map? honours;
|
|
||||||
|
|
||||||
AccountListModel.fromJson(Map<String, dynamic> json) {
|
|
||||||
mid = json['mid'];
|
|
||||||
name = json['name'] ?? '';
|
|
||||||
sex = json['sex'];
|
|
||||||
face = json['face'];
|
|
||||||
sign = json['sign'];
|
|
||||||
rank = json['rank'];
|
|
||||||
level = json['level'];
|
|
||||||
silence = json['silence'];
|
|
||||||
vip = json['vip'];
|
|
||||||
pendant = json['pendant'];
|
|
||||||
nameplate = json['nameplate'];
|
|
||||||
official = json['official'];
|
|
||||||
birthday = json['birthday'];
|
|
||||||
isFakeAccount = json['is_fake_account'];
|
|
||||||
isDeleted = json['is_deleted'];
|
|
||||||
inRegAudit = json['in_reg_audit'];
|
|
||||||
faceNft = json['face_nft'];
|
|
||||||
faceNftNew = json['face_nft_new'];
|
|
||||||
isSeniorMember = json['is_senior_member'];
|
|
||||||
digitalId = json['digital_id'];
|
|
||||||
digitalType = json['digital_type'];
|
|
||||||
attestation = json['attestation'];
|
|
||||||
expertInfo = json['expert_info'];
|
|
||||||
honours = json['honours'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,226 +0,0 @@
|
|||||||
import 'dart:convert';
|
|
||||||
|
|
||||||
import 'package:pilipala/models/msg/account.dart';
|
|
||||||
|
|
||||||
class SessionDataModel {
|
|
||||||
SessionDataModel({
|
|
||||||
this.sessionList,
|
|
||||||
this.hasMore,
|
|
||||||
});
|
|
||||||
|
|
||||||
List? sessionList;
|
|
||||||
int? hasMore;
|
|
||||||
|
|
||||||
SessionDataModel.fromJson(Map<String, dynamic> json) {
|
|
||||||
sessionList = json['session_list']
|
|
||||||
?.map<SessionList>((e) => SessionList.fromJson(e))
|
|
||||||
.toList();
|
|
||||||
hasMore = json['has_more'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SessionList {
|
|
||||||
SessionList({
|
|
||||||
this.talkerId,
|
|
||||||
this.sessionType,
|
|
||||||
this.atSeqno,
|
|
||||||
this.topTs,
|
|
||||||
this.groupName,
|
|
||||||
this.groupCover,
|
|
||||||
this.isFollow,
|
|
||||||
this.isDnd,
|
|
||||||
this.ackSeqno,
|
|
||||||
this.ackTs,
|
|
||||||
this.sessionTs,
|
|
||||||
this.unreadCount,
|
|
||||||
this.lastMsg,
|
|
||||||
this.groupType,
|
|
||||||
this.canFold,
|
|
||||||
this.status,
|
|
||||||
this.maxSeqno,
|
|
||||||
this.newPushMsg,
|
|
||||||
this.setting,
|
|
||||||
this.isGuardian,
|
|
||||||
this.isIntercept,
|
|
||||||
this.isTrust,
|
|
||||||
this.systemMsgType,
|
|
||||||
this.liveStatus,
|
|
||||||
this.bizMsgUnreadCount,
|
|
||||||
// this.userLabel,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? talkerId;
|
|
||||||
int? sessionType;
|
|
||||||
int? atSeqno;
|
|
||||||
int? topTs;
|
|
||||||
String? groupName;
|
|
||||||
String? groupCover;
|
|
||||||
int? isFollow;
|
|
||||||
int? isDnd;
|
|
||||||
int? ackSeqno;
|
|
||||||
int? ackTs;
|
|
||||||
int? sessionTs;
|
|
||||||
int? unreadCount;
|
|
||||||
LastMsg? lastMsg;
|
|
||||||
int? groupType;
|
|
||||||
int? canFold;
|
|
||||||
int? status;
|
|
||||||
int? maxSeqno;
|
|
||||||
int? newPushMsg;
|
|
||||||
int? setting;
|
|
||||||
int? isGuardian;
|
|
||||||
int? isIntercept;
|
|
||||||
int? isTrust;
|
|
||||||
int? systemMsgType;
|
|
||||||
int? liveStatus;
|
|
||||||
int? bizMsgUnreadCount;
|
|
||||||
// int? userLabel;
|
|
||||||
AccountListModel? accountInfo;
|
|
||||||
|
|
||||||
SessionList.fromJson(Map<String, dynamic> json) {
|
|
||||||
talkerId = json["talker_id"];
|
|
||||||
sessionType = json["session_type"];
|
|
||||||
atSeqno = json["at_seqno"];
|
|
||||||
topTs = json["top_ts"];
|
|
||||||
groupName = json["group_name"];
|
|
||||||
groupCover = json["group_cover"];
|
|
||||||
isFollow = json["is_follow"];
|
|
||||||
isDnd = json["is_dnd"];
|
|
||||||
ackSeqno = json["ack_seqno"];
|
|
||||||
ackTs = json["ack_ts"];
|
|
||||||
sessionTs = json["session_ts"];
|
|
||||||
unreadCount = json["unread_count"];
|
|
||||||
lastMsg =
|
|
||||||
json["last_msg"] != null ? LastMsg.fromJson(json["last_msg"]) : null;
|
|
||||||
groupType = json["group_type"];
|
|
||||||
canFold = json["can_fold"];
|
|
||||||
status = json["status"];
|
|
||||||
maxSeqno = json["max_seqno"];
|
|
||||||
newPushMsg = json["new_push_msg"];
|
|
||||||
setting = json["setting"];
|
|
||||||
isGuardian = json["is_guardian"];
|
|
||||||
isIntercept = json["is_intercept"];
|
|
||||||
isTrust = json["is_trust"];
|
|
||||||
systemMsgType = json["system_msg_type"];
|
|
||||||
liveStatus = json["live_status"];
|
|
||||||
bizMsgUnreadCount = json["biz_msg_unread_count"];
|
|
||||||
// userLabel = json["user_label"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class LastMsg {
|
|
||||||
LastMsg({
|
|
||||||
this.senderIid,
|
|
||||||
this.receiverType,
|
|
||||||
this.receiverId,
|
|
||||||
this.msgType,
|
|
||||||
this.content,
|
|
||||||
this.msgSeqno,
|
|
||||||
this.timestamp,
|
|
||||||
this.atUids,
|
|
||||||
this.msgKey,
|
|
||||||
this.msgStatus,
|
|
||||||
this.notifyCode,
|
|
||||||
this.newFaceVersion,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? senderIid;
|
|
||||||
int? receiverType;
|
|
||||||
int? receiverId;
|
|
||||||
int? msgType;
|
|
||||||
Map? content;
|
|
||||||
int? msgSeqno;
|
|
||||||
int? timestamp;
|
|
||||||
String? atUids;
|
|
||||||
int? msgKey;
|
|
||||||
int? msgStatus;
|
|
||||||
String? notifyCode;
|
|
||||||
int? newFaceVersion;
|
|
||||||
|
|
||||||
LastMsg.fromJson(Map<String, dynamic> json) {
|
|
||||||
senderIid = json['sender_uid'];
|
|
||||||
receiverType = json['receiver_type'];
|
|
||||||
receiverId = json['receiver_id'];
|
|
||||||
msgType = json['msg_type'];
|
|
||||||
content = jsonDecode(json['content']);
|
|
||||||
msgSeqno = json['msg_seqno'];
|
|
||||||
timestamp = json['timestamp'];
|
|
||||||
atUids = json['at_uids'];
|
|
||||||
msgKey = json['msg_key'];
|
|
||||||
msgStatus = json['msg_status'];
|
|
||||||
notifyCode = json['notify_code'];
|
|
||||||
newFaceVersion = json['new_face_version'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SessionMsgDataModel {
|
|
||||||
SessionMsgDataModel({
|
|
||||||
this.messages,
|
|
||||||
this.hasMore,
|
|
||||||
this.minSeqno,
|
|
||||||
this.maxSeqno,
|
|
||||||
this.eInfos,
|
|
||||||
});
|
|
||||||
|
|
||||||
List<MessageItem>? messages;
|
|
||||||
int? hasMore;
|
|
||||||
int? minSeqno;
|
|
||||||
int? maxSeqno;
|
|
||||||
List? eInfos;
|
|
||||||
|
|
||||||
SessionMsgDataModel.fromJson(Map<String, dynamic> json) {
|
|
||||||
messages = json['messages']
|
|
||||||
.map<MessageItem>((e) => MessageItem.fromJson(e))
|
|
||||||
.toList();
|
|
||||||
hasMore = json['has_more'];
|
|
||||||
minSeqno = json['min_seqno'];
|
|
||||||
maxSeqno = json['max_seqno'];
|
|
||||||
eInfos = json['e_infos'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MessageItem {
|
|
||||||
MessageItem({
|
|
||||||
this.senderUid,
|
|
||||||
this.receiverType,
|
|
||||||
this.receiverId,
|
|
||||||
this.msgType,
|
|
||||||
this.content,
|
|
||||||
this.msgSeqno,
|
|
||||||
this.timestamp,
|
|
||||||
this.atUids,
|
|
||||||
this.msgKey,
|
|
||||||
this.msgStatus,
|
|
||||||
this.notifyCode,
|
|
||||||
this.newFaceVersion,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? senderUid;
|
|
||||||
int? receiverType;
|
|
||||||
int? receiverId;
|
|
||||||
int? msgType;
|
|
||||||
dynamic content;
|
|
||||||
int? msgSeqno;
|
|
||||||
int? timestamp;
|
|
||||||
List? atUids;
|
|
||||||
int? msgKey;
|
|
||||||
int? msgStatus;
|
|
||||||
String? notifyCode;
|
|
||||||
int? newFaceVersion;
|
|
||||||
|
|
||||||
MessageItem.fromJson(Map<String, dynamic> json) {
|
|
||||||
senderUid = json['sender_uid'];
|
|
||||||
receiverType = json['receiver_type'];
|
|
||||||
receiverId = json['receiver_id'];
|
|
||||||
// 1 文本 2 图片 18 系统提示 10 系统通知 5 撤回的消息
|
|
||||||
msgType = json['msg_type'];
|
|
||||||
content = jsonDecode(json['content']);
|
|
||||||
msgSeqno = json['msg_seqno'];
|
|
||||||
timestamp = json['timestamp'];
|
|
||||||
atUids = json['at_uids'];
|
|
||||||
msgKey = json['msg_key'];
|
|
||||||
msgStatus = json['msg_status'];
|
|
||||||
notifyCode = json['notify_code'];
|
|
||||||
newFaceVersion = json['new_face_version'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,80 +0,0 @@
|
|||||||
class AiConclusionModel {
|
|
||||||
AiConclusionModel({
|
|
||||||
this.code,
|
|
||||||
this.modelResult,
|
|
||||||
this.stid,
|
|
||||||
this.status,
|
|
||||||
this.likeNum,
|
|
||||||
this.dislikeNum,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? code;
|
|
||||||
ModelResult? modelResult;
|
|
||||||
String? stid;
|
|
||||||
int? status;
|
|
||||||
int? likeNum;
|
|
||||||
int? dislikeNum;
|
|
||||||
|
|
||||||
AiConclusionModel.fromJson(Map<String, dynamic> json) {
|
|
||||||
code = json['code'];
|
|
||||||
modelResult = ModelResult.fromJson(json['model_result']);
|
|
||||||
stid = json['stid'];
|
|
||||||
status = json['status'];
|
|
||||||
likeNum = json['like_num'];
|
|
||||||
dislikeNum = json['dislike_num'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ModelResult {
|
|
||||||
ModelResult({
|
|
||||||
this.resultType,
|
|
||||||
this.summary,
|
|
||||||
this.outline,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? resultType;
|
|
||||||
String? summary;
|
|
||||||
List<OutlineItem>? outline;
|
|
||||||
|
|
||||||
ModelResult.fromJson(Map<String, dynamic> json) {
|
|
||||||
resultType = json['result_type'];
|
|
||||||
summary = json['summary'];
|
|
||||||
outline = json['result_type'] == 2
|
|
||||||
? json['outline']
|
|
||||||
.map<OutlineItem>((e) => OutlineItem.fromJson(e))
|
|
||||||
.toList()
|
|
||||||
: <OutlineItem>[];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class OutlineItem {
|
|
||||||
OutlineItem({
|
|
||||||
this.title,
|
|
||||||
this.partOutline,
|
|
||||||
});
|
|
||||||
|
|
||||||
String? title;
|
|
||||||
List<PartOutline>? partOutline;
|
|
||||||
|
|
||||||
OutlineItem.fromJson(Map<String, dynamic> json) {
|
|
||||||
title = json['title'];
|
|
||||||
partOutline = json['part_outline']
|
|
||||||
.map<PartOutline>((e) => PartOutline.fromJson(e))
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PartOutline {
|
|
||||||
PartOutline({
|
|
||||||
this.timestamp,
|
|
||||||
this.content,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? timestamp;
|
|
||||||
String? content;
|
|
||||||
|
|
||||||
PartOutline.fromJson(Map<String, dynamic> json) {
|
|
||||||
timestamp = json['timestamp'];
|
|
||||||
content = json['content'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,3 +1,5 @@
|
|||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:pilipala/models/video/play/quality.dart';
|
import 'package:pilipala/models/video/play/quality.dart';
|
||||||
|
|
||||||
class PlayUrlModel {
|
class PlayUrlModel {
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
@ -31,6 +34,11 @@ class _AboutPageState extends State<AboutPage> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
|
Divider(
|
||||||
|
thickness: 8,
|
||||||
|
height: 10,
|
||||||
|
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||||
|
),
|
||||||
Image.asset(
|
Image.asset(
|
||||||
'assets/images/logo/logo_android_2.png',
|
'assets/images/logo/logo_android_2.png',
|
||||||
width: 150,
|
width: 150,
|
||||||
@ -75,9 +83,9 @@ class _AboutPageState extends State<AboutPage> {
|
|||||||
// ),
|
// ),
|
||||||
// ),
|
// ),
|
||||||
Divider(
|
Divider(
|
||||||
thickness: 1,
|
thickness: 8,
|
||||||
height: 30,
|
height: 30,
|
||||||
color: Theme.of(context).colorScheme.outlineVariant,
|
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
onTap: () => _aboutController.githubUrl(),
|
onTap: () => _aboutController.githubUrl(),
|
||||||
@ -126,6 +134,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),
|
||||||
),
|
),
|
||||||
|
Divider(
|
||||||
|
thickness: 8,
|
||||||
|
height: 30,
|
||||||
|
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -171,7 +184,7 @@ class AboutController extends GetxController {
|
|||||||
|
|
||||||
// 获取远程版本
|
// 获取远程版本
|
||||||
Future getRemoteApp() async {
|
Future getRemoteApp() async {
|
||||||
var result = await Request().get(Api.latestApp, extra: {'ua': 'pc'});
|
var result = await Request().get(Api.latestApp);
|
||||||
data = LatestDataModel.fromJson(result.data);
|
data = LatestDataModel.fromJson(result.data);
|
||||||
remoteAppInfo = data;
|
remoteAppInfo = data;
|
||||||
remoteVersion.value = data.tagName!;
|
remoteVersion.value = data.tagName!;
|
||||||
|
|||||||
@ -22,7 +22,7 @@ class BangumiIntroController extends GetxController {
|
|||||||
? int.parse(Get.parameters['seasonId']!)
|
? int.parse(Get.parameters['seasonId']!)
|
||||||
: null;
|
: null;
|
||||||
var epId = Get.parameters['epId'] != null
|
var epId = Get.parameters['epId'] != null
|
||||||
? int.tryParse(Get.parameters['epId']!)
|
? int.parse(Get.parameters['epId']!)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
// 是否预渲染 骨架屏
|
// 是否预渲染 骨架屏
|
||||||
@ -258,7 +258,7 @@ class BangumiIntroController extends GetxController {
|
|||||||
VideoDetailController videoDetailCtr =
|
VideoDetailController videoDetailCtr =
|
||||||
Get.find<VideoDetailController>(tag: Get.arguments['heroTag']);
|
Get.find<VideoDetailController>(tag: Get.arguments['heroTag']);
|
||||||
videoDetailCtr.bvid = bvid;
|
videoDetailCtr.bvid = bvid;
|
||||||
videoDetailCtr.cid.value = cid;
|
videoDetailCtr.cid = cid;
|
||||||
videoDetailCtr.danmakuCid.value = cid;
|
videoDetailCtr.danmakuCid.value = cid;
|
||||||
videoDetailCtr.queryVideoUrl();
|
videoDetailCtr.queryVideoUrl();
|
||||||
// 重新请求评论
|
// 重新请求评论
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import 'package:get/get.dart';
|
|||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.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/http_error.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
import 'package:pilipala/common/widgets/stat/danmu.dart';
|
import 'package:pilipala/common/widgets/stat/danmu.dart';
|
||||||
import 'package:pilipala/common/widgets/stat/view.dart';
|
import 'package:pilipala/common/widgets/stat/view.dart';
|
||||||
@ -33,12 +34,10 @@ class BangumiIntroPanel extends StatefulWidget {
|
|||||||
|
|
||||||
class _BangumiIntroPanelState extends State<BangumiIntroPanel>
|
class _BangumiIntroPanelState extends State<BangumiIntroPanel>
|
||||||
with AutomaticKeepAliveClientMixin {
|
with AutomaticKeepAliveClientMixin {
|
||||||
late BangumiIntroController bangumiIntroController;
|
final BangumiIntroController bangumiIntroController =
|
||||||
late VideoDetailController videoDetailCtr;
|
Get.put(BangumiIntroController(), tag: Get.arguments['heroTag']);
|
||||||
BangumiInfoModel? bangumiDetail;
|
BangumiInfoModel? bangumiDetail;
|
||||||
late Future _futureBuilderFuture;
|
late Future _futureBuilderFuture;
|
||||||
late int cid;
|
|
||||||
late String heroTag;
|
|
||||||
|
|
||||||
// 添加页面缓存
|
// 添加页面缓存
|
||||||
@override
|
@override
|
||||||
@ -47,19 +46,10 @@ class _BangumiIntroPanelState extends State<BangumiIntroPanel>
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
heroTag = Get.arguments['heroTag'];
|
|
||||||
cid = widget.cid!;
|
|
||||||
bangumiIntroController = Get.put(BangumiIntroController(), tag: heroTag);
|
|
||||||
videoDetailCtr = Get.find<VideoDetailController>(tag: heroTag);
|
|
||||||
bangumiIntroController.bangumiDetail.listen((value) {
|
bangumiIntroController.bangumiDetail.listen((value) {
|
||||||
bangumiDetail = value;
|
bangumiDetail = value;
|
||||||
});
|
});
|
||||||
_futureBuilderFuture = bangumiIntroController.queryBangumiIntro();
|
_futureBuilderFuture = bangumiIntroController.queryBangumiIntro();
|
||||||
videoDetailCtr.cid.listen((p0) {
|
|
||||||
print('🐶🐶$p0');
|
|
||||||
cid = p0;
|
|
||||||
setState(() {});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -71,25 +61,22 @@ class _BangumiIntroPanelState extends State<BangumiIntroPanel>
|
|||||||
if (snapshot.connectionState == ConnectionState.done) {
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
if (snapshot.data['status']) {
|
if (snapshot.data['status']) {
|
||||||
// 请求成功
|
// 请求成功
|
||||||
|
|
||||||
return BangumiInfo(
|
return BangumiInfo(
|
||||||
loadingStatus: false,
|
loadingStatus: false,
|
||||||
bangumiDetail: bangumiDetail,
|
bangumiDetail: bangumiDetail,
|
||||||
cid: cid,
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// 请求错误
|
// 请求错误
|
||||||
// return HttpError(
|
return HttpError(
|
||||||
// errMsg: snapshot.data['msg'],
|
errMsg: snapshot.data['msg'],
|
||||||
// fn: () => Get.back(),
|
fn: () => Get.back(),
|
||||||
// );
|
);
|
||||||
return SizedBox();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return BangumiInfo(
|
return BangumiInfo(
|
||||||
loadingStatus: true,
|
loadingStatus: true,
|
||||||
bangumiDetail: bangumiDetail,
|
bangumiDetail: bangumiDetail,
|
||||||
cid: cid,
|
cid: widget.cid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -121,14 +108,7 @@ class _BangumiInfoState extends State<BangumiInfo> {
|
|||||||
late final BangumiInfoModel? bangumiItem;
|
late final BangumiInfoModel? bangumiItem;
|
||||||
late double sheetHeight;
|
late double sheetHeight;
|
||||||
int? cid;
|
int? cid;
|
||||||
bool isProcessing = false;
|
|
||||||
void Function()? handleState(Future Function() action) {
|
|
||||||
return isProcessing ? null : () async {
|
|
||||||
setState(() => isProcessing = true);
|
|
||||||
await action();
|
|
||||||
setState(() => isProcessing = false);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -137,12 +117,6 @@ class _BangumiInfoState extends State<BangumiInfo> {
|
|||||||
bangumiItem = bangumiIntroController.bangumiItem;
|
bangumiItem = bangumiIntroController.bangumiItem;
|
||||||
sheetHeight = localCache.get('sheetHeight');
|
sheetHeight = localCache.get('sheetHeight');
|
||||||
cid = widget.cid!;
|
cid = widget.cid!;
|
||||||
print('cid: $cid');
|
|
||||||
videoDetailCtr.cid.listen((p0) {
|
|
||||||
cid = p0;
|
|
||||||
print('cid: $cid');
|
|
||||||
setState(() {});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 收藏
|
// 收藏
|
||||||
@ -286,15 +260,9 @@ class _BangumiInfoState extends State<BangumiInfo> {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
!widget.loadingStatus
|
!widget.loadingStatus
|
||||||
? (widget.bangumiDetail!.areas!
|
|
||||||
.isNotEmpty
|
|
||||||
? widget.bangumiDetail!.areas!
|
? widget.bangumiDetail!.areas!
|
||||||
.first['name']
|
.first['name']
|
||||||
: '')
|
: bangumiItem!.areas!.first['name'],
|
||||||
: (bangumiItem!.areas!.isNotEmpty
|
|
||||||
? bangumiItem!
|
|
||||||
.areas!.first['name']
|
|
||||||
: ''),
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: t.colorScheme.outline,
|
color: t.colorScheme.outline,
|
||||||
@ -402,7 +370,7 @@ class _BangumiInfoState extends State<BangumiInfo> {
|
|||||||
() => ActionItem(
|
() => ActionItem(
|
||||||
icon: const Icon(FontAwesomeIcons.thumbsUp),
|
icon: const Icon(FontAwesomeIcons.thumbsUp),
|
||||||
selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp),
|
selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp),
|
||||||
onTap: handleState(bangumiIntroController.actionLikeVideo),
|
onTap: () => bangumiIntroController.actionLikeVideo(),
|
||||||
selectStatus: bangumiIntroController.hasLike.value,
|
selectStatus: bangumiIntroController.hasLike.value,
|
||||||
loadingStatus: false,
|
loadingStatus: false,
|
||||||
text: !widget.loadingStatus
|
text: !widget.loadingStatus
|
||||||
@ -413,7 +381,7 @@ class _BangumiInfoState extends State<BangumiInfo> {
|
|||||||
() => ActionItem(
|
() => ActionItem(
|
||||||
icon: const Icon(FontAwesomeIcons.b),
|
icon: const Icon(FontAwesomeIcons.b),
|
||||||
selectIcon: const Icon(FontAwesomeIcons.b),
|
selectIcon: const Icon(FontAwesomeIcons.b),
|
||||||
onTap: handleState(bangumiIntroController.actionCoinVideo),
|
onTap: () => bangumiIntroController.actionCoinVideo(),
|
||||||
selectStatus: bangumiIntroController.hasCoin.value,
|
selectStatus: bangumiIntroController.hasCoin.value,
|
||||||
loadingStatus: false,
|
loadingStatus: false,
|
||||||
text: !widget.loadingStatus
|
text: !widget.loadingStatus
|
||||||
@ -462,7 +430,7 @@ class _BangumiInfoState extends State<BangumiInfo> {
|
|||||||
Obx(
|
Obx(
|
||||||
() => ActionRowItem(
|
() => ActionRowItem(
|
||||||
icon: const Icon(FontAwesomeIcons.thumbsUp),
|
icon: const Icon(FontAwesomeIcons.thumbsUp),
|
||||||
onTap: handleState(videoIntroController.actionLikeVideo),
|
onTap: () => videoIntroController.actionLikeVideo(),
|
||||||
selectStatus: videoIntroController.hasLike.value,
|
selectStatus: videoIntroController.hasLike.value,
|
||||||
loadingStatus: widget.loadingStatus,
|
loadingStatus: widget.loadingStatus,
|
||||||
text: !widget.loadingStatus
|
text: !widget.loadingStatus
|
||||||
@ -474,7 +442,7 @@ class _BangumiInfoState extends State<BangumiInfo> {
|
|||||||
Obx(
|
Obx(
|
||||||
() => ActionRowItem(
|
() => ActionRowItem(
|
||||||
icon: const Icon(FontAwesomeIcons.b),
|
icon: const Icon(FontAwesomeIcons.b),
|
||||||
onTap: handleState(videoIntroController.actionCoinVideo),
|
onTap: () => videoIntroController.actionCoinVideo(),
|
||||||
selectStatus: videoIntroController.hasCoin.value,
|
selectStatus: videoIntroController.hasCoin.value,
|
||||||
loadingStatus: widget.loadingStatus,
|
loadingStatus: widget.loadingStatus,
|
||||||
text: !widget.loadingStatus
|
text: !widget.loadingStatus
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import 'package:flutter/rendering.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/common/constants.dart';
|
import 'package:pilipala/common/constants.dart';
|
||||||
import 'package:pilipala/common/widgets/http_error.dart';
|
import 'package:pilipala/common/widgets/http_error.dart';
|
||||||
import 'package:pilipala/pages/home/index.dart';
|
|
||||||
import 'package:pilipala/pages/main/index.dart';
|
import 'package:pilipala/pages/main/index.dart';
|
||||||
import 'package:pilipala/pages/rcmd/view.dart';
|
import 'package:pilipala/pages/rcmd/view.dart';
|
||||||
|
|
||||||
@ -36,8 +35,6 @@ class _BangumiPageState extends State<BangumiPage>
|
|||||||
scrollController = _bangumidController.scrollController;
|
scrollController = _bangumidController.scrollController;
|
||||||
StreamController<bool> mainStream =
|
StreamController<bool> mainStream =
|
||||||
Get.find<MainController>().bottomBarStream;
|
Get.find<MainController>().bottomBarStream;
|
||||||
StreamController<bool> searchBarStream =
|
|
||||||
Get.find<HomeController>().searchBarStream;
|
|
||||||
_futureBuilderFuture = _bangumidController.queryBangumiListFeed();
|
_futureBuilderFuture = _bangumidController.queryBangumiListFeed();
|
||||||
_futureBuilderFutureFollow = _bangumidController.queryBangumiFollow();
|
_futureBuilderFutureFollow = _bangumidController.queryBangumiFollow();
|
||||||
scrollController.addListener(
|
scrollController.addListener(
|
||||||
@ -54,10 +51,8 @@ class _BangumiPageState extends State<BangumiPage>
|
|||||||
scrollController.position.userScrollDirection;
|
scrollController.position.userScrollDirection;
|
||||||
if (direction == ScrollDirection.forward) {
|
if (direction == ScrollDirection.forward) {
|
||||||
mainStream.add(true);
|
mainStream.add(true);
|
||||||
searchBarStream.add(true);
|
|
||||||
} else if (direction == ScrollDirection.reverse) {
|
} else if (direction == ScrollDirection.reverse) {
|
||||||
mainStream.add(false);
|
mainStream.add(false);
|
||||||
searchBarStream.add(false);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -206,7 +201,7 @@ class _BangumiPageState extends State<BangumiPage>
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
LoadingMore()
|
const LoadingMore()
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,11 +1,8 @@
|
|||||||
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:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:pilipala/models/bangumi/info.dart';
|
import 'package:pilipala/models/bangumi/info.dart';
|
||||||
import 'package:pilipala/pages/video/detail/index.dart';
|
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
|
||||||
|
|
||||||
class BangumiPanel extends StatefulWidget {
|
class BangumiPanel extends StatefulWidget {
|
||||||
final List<EpisodeItem> pages;
|
final List<EpisodeItem> pages;
|
||||||
@ -33,29 +30,16 @@ class _BangumiPanelState extends State<BangumiPanel> {
|
|||||||
dynamic userInfo;
|
dynamic userInfo;
|
||||||
// 默认未开通
|
// 默认未开通
|
||||||
int vipStatus = 0;
|
int vipStatus = 0;
|
||||||
late int cid;
|
|
||||||
String heroTag = Get.arguments['heroTag'];
|
|
||||||
late final VideoDetailController videoDetailCtr;
|
|
||||||
final ItemScrollController itemScrollController = ItemScrollController();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
cid = widget.cid!;
|
currentIndex = widget.pages.indexWhere((e) => e.cid == widget.cid!);
|
||||||
currentIndex = widget.pages.indexWhere((e) => e.cid == cid);
|
|
||||||
scrollToIndex();
|
scrollToIndex();
|
||||||
userInfo = userInfoCache.get('userInfoCache');
|
userInfo = userInfoCache.get('userInfoCache');
|
||||||
if (userInfo != null) {
|
if (userInfo != null) {
|
||||||
vipStatus = userInfo.vipStatus;
|
vipStatus = userInfo.vipStatus;
|
||||||
}
|
}
|
||||||
videoDetailCtr = Get.find<VideoDetailController>(tag: heroTag);
|
|
||||||
|
|
||||||
videoDetailCtr.cid.listen((p0) {
|
|
||||||
cid = p0;
|
|
||||||
setState(() {});
|
|
||||||
currentIndex = widget.pages.indexWhere((e) => e.cid == cid);
|
|
||||||
scrollToIndex();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -72,11 +56,10 @@ class _BangumiPanelState extends State<BangumiPanel> {
|
|||||||
return StatefulBuilder(
|
return StatefulBuilder(
|
||||||
builder: (BuildContext context, StateSetter setState) {
|
builder: (BuildContext context, StateSetter setState) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
// await Future.delayed(const Duration(milliseconds: 200));
|
await Future.delayed(const Duration(milliseconds: 200));
|
||||||
// listViewScrollCtr_2.animateTo(currentIndex * 56,
|
listViewScrollCtr_2.animateTo(currentIndex * 56,
|
||||||
// duration: const Duration(milliseconds: 500),
|
duration: const Duration(milliseconds: 500),
|
||||||
// curve: Curves.easeInOut);
|
curve: Curves.easeInOut);
|
||||||
itemScrollController.jumpTo(index: currentIndex);
|
|
||||||
});
|
});
|
||||||
// 在这里使用 setState 更新状态
|
// 在这里使用 setState 更新状态
|
||||||
return Container(
|
return Container(
|
||||||
@ -104,9 +87,11 @@ class _BangumiPanelState extends State<BangumiPanel> {
|
|||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Material(
|
child: Material(
|
||||||
child: ScrollablePositionedList.builder(
|
child: ListView.builder(
|
||||||
|
controller: listViewScrollCtr_2,
|
||||||
itemCount: widget.pages.length,
|
itemCount: widget.pages.length,
|
||||||
itemBuilder: (context, index) => ListTile(
|
itemBuilder: (context, index) {
|
||||||
|
return ListTile(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
changeFucCall(widget.pages[index], index);
|
changeFucCall(widget.pages[index], index);
|
||||||
@ -116,7 +101,8 @@ class _BangumiPanelState extends State<BangumiPanel> {
|
|||||||
leading: index == currentIndex
|
leading: index == currentIndex
|
||||||
? Image.asset(
|
? Image.asset(
|
||||||
'assets/images/live.gif',
|
'assets/images/live.gif',
|
||||||
color: Theme.of(context).colorScheme.primary,
|
color:
|
||||||
|
Theme.of(context).colorScheme.primary,
|
||||||
height: 12,
|
height: 12,
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
@ -135,8 +121,8 @@ class _BangumiPanelState extends State<BangumiPanel> {
|
|||||||
height: 20,
|
height: 20,
|
||||||
)
|
)
|
||||||
: const SizedBox(),
|
: const SizedBox(),
|
||||||
),
|
);
|
||||||
itemScrollController: itemScrollController,
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -236,7 +222,7 @@ class _BangumiPanelState extends State<BangumiPanel> {
|
|||||||
children: [
|
children: [
|
||||||
if (i == currentIndex) ...[
|
if (i == currentIndex) ...[
|
||||||
Image.asset(
|
Image.asset(
|
||||||
'assets/images/live.png',
|
'assets/images/live.gif',
|
||||||
color:
|
color:
|
||||||
Theme.of(context).colorScheme.primary,
|
Theme.of(context).colorScheme.primary,
|
||||||
height: 12,
|
height: 12,
|
||||||
|
|||||||
@ -62,7 +62,7 @@ class BangumiCardV extends StatelessWidget {
|
|||||||
arguments: {
|
arguments: {
|
||||||
'pic': pic,
|
'pic': pic,
|
||||||
'heroTag': heroTag,
|
'heroTag': heroTag,
|
||||||
'videoType': SearchType.media_bangumi,
|
// 'videoType': SearchType.media_bangumi,
|
||||||
'bangumiItem': res['data'],
|
'bangumiItem': res['data'],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@ -3,56 +3,62 @@ import 'package:pilipala/models/danmaku/dm.pb.dart';
|
|||||||
import 'package:pilipala/plugin/pl_player/index.dart';
|
import 'package:pilipala/plugin/pl_player/index.dart';
|
||||||
|
|
||||||
class PlDanmakuController {
|
class PlDanmakuController {
|
||||||
PlDanmakuController(this.cid);
|
PlDanmakuController(this.cid, this.playerController);
|
||||||
final int cid;
|
final int cid;
|
||||||
Map<int,List<DanmakuElem>> dmSegMap = {};
|
final PlPlayerController playerController;
|
||||||
// 已请求的段落标记
|
late Duration videoDuration;
|
||||||
List<bool> requestedSeg = [];
|
// 按 6min 分段
|
||||||
|
int segCount = 0;
|
||||||
|
List<DmSegMobileReply> dmSegList = [];
|
||||||
|
int currentSegIndex = 0;
|
||||||
|
int currentDmIndex = 0;
|
||||||
|
|
||||||
bool get initiated => requestedSeg.isNotEmpty;
|
void calcSegment() {
|
||||||
|
segCount = (videoDuration.inSeconds / (60 * 6)).ceil();
|
||||||
static int SEGMENT_LENGTH = 60 * 6 * 1000;
|
|
||||||
|
|
||||||
void initiate(int videoDuration, int progress) {
|
|
||||||
if (requestedSeg.isEmpty) {
|
|
||||||
int segCount = (videoDuration / SEGMENT_LENGTH).ceil();
|
|
||||||
requestedSeg = List<bool>.generate(segCount, (index) => false);
|
|
||||||
}
|
|
||||||
queryDanmaku(
|
|
||||||
calcSegment(progress)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispose() {
|
Future<List<DmSegMobileReply>> queryDanmaku() async {
|
||||||
dmSegMap.clear();
|
dmSegList.clear();
|
||||||
requestedSeg.clear();
|
for (int segIndex = 1; segIndex <= segCount; segIndex++) {
|
||||||
}
|
|
||||||
|
|
||||||
int calcSegment(int progress) {
|
|
||||||
return progress ~/ SEGMENT_LENGTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
void queryDanmaku(int segmentIndex) async {
|
|
||||||
assert(requestedSeg[segmentIndex] == false);
|
|
||||||
requestedSeg[segmentIndex] = true;
|
|
||||||
DmSegMobileReply result =
|
DmSegMobileReply result =
|
||||||
await DanmakaHttp.queryDanmaku(cid: cid, segmentIndex: segmentIndex + 1);
|
await DanmakaHttp.queryDanmaku(cid: cid, segmentIndex: segIndex);
|
||||||
if (result.elems.isNotEmpty) {
|
if (result.elems.isNotEmpty) {
|
||||||
for (var element in result.elems) {
|
result.elems.sort((a, b) => (a.progress).compareTo(b.progress));
|
||||||
int pos = element.progress ~/ 100;//每0.1秒存储一次
|
dmSegList.add(result);
|
||||||
if (dmSegMap[pos] == null) {
|
|
||||||
dmSegMap[pos] = [];
|
|
||||||
}
|
}
|
||||||
dmSegMap[pos]!.add(element);
|
|
||||||
}
|
}
|
||||||
|
if (dmSegList.isNotEmpty) {
|
||||||
|
findClosestPositionIndex(playerController.position.value.inMilliseconds);
|
||||||
|
}
|
||||||
|
return dmSegList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 查询当前最接近的弹幕
|
||||||
|
void findClosestPositionIndex(int position) {
|
||||||
|
int segIndex = (position / (6 * 60 * 1000)).ceil() - 1;
|
||||||
|
if (segIndex < 0) segIndex = 0;
|
||||||
|
List elems = dmSegList[segIndex].elems;
|
||||||
|
|
||||||
|
if (segIndex < dmSegList.length) {
|
||||||
|
int left = 0;
|
||||||
|
int right = elems.length;
|
||||||
|
|
||||||
|
while (left < right) {
|
||||||
|
int mid = (right + left) ~/ 2;
|
||||||
|
var midPosition = elems[mid].progress;
|
||||||
|
|
||||||
|
if (midPosition >= position) {
|
||||||
|
right = mid;
|
||||||
|
} else {
|
||||||
|
left = mid + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<DanmakuElem>? getCurrentDanmaku(int progress) {
|
currentSegIndex = segIndex;
|
||||||
int segmentIndex = calcSegment(progress);
|
currentDmIndex = right;
|
||||||
if (!requestedSeg[segmentIndex]) {
|
} else {
|
||||||
queryDanmaku(segmentIndex);
|
currentSegIndex = segIndex;
|
||||||
}
|
currentDmIndex = 0;
|
||||||
return dmSegMap[progress ~/ 100];
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
import 'package:easy_debounce/easy_throttle.dart';
|
|
||||||
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:ns_danmaku/ns_danmaku.dart';
|
import 'package:ns_danmaku/ns_danmaku.dart';
|
||||||
import 'package:pilipala/models/danmaku/dm.pb.dart';
|
|
||||||
import 'package:pilipala/pages/danmaku/index.dart';
|
import 'package:pilipala/pages/danmaku/index.dart';
|
||||||
import 'package:pilipala/plugin/pl_player/index.dart';
|
import 'package:pilipala/plugin/pl_player/index.dart';
|
||||||
import 'package:pilipala/utils/danmaku.dart';
|
import 'package:pilipala/utils/danmaku.dart';
|
||||||
@ -28,15 +26,14 @@ class _PlDanmakuState extends State<PlDanmaku> {
|
|||||||
late PlPlayerController playerController;
|
late PlPlayerController playerController;
|
||||||
late PlDanmakuController _plDanmakuController;
|
late PlDanmakuController _plDanmakuController;
|
||||||
DanmakuController? _controller;
|
DanmakuController? _controller;
|
||||||
// bool danmuPlayStatus = true;
|
bool danmuPlayStatus = true;
|
||||||
Box setting = GStrorage.setting;
|
Box setting = GStrorage.setting;
|
||||||
late bool enableShowDanmaku;
|
late bool enableShowDanmaku;
|
||||||
late List blockTypes;
|
late List blockTypes;
|
||||||
late double showArea;
|
late double showArea;
|
||||||
late double opacityVal;
|
late double opacityVal;
|
||||||
late double fontSizeVal;
|
late double fontSizeVal;
|
||||||
late double danmakuDurationVal;
|
late double danmakuSpeedVal;
|
||||||
int latestAddedPosition = -1;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -44,32 +41,33 @@ class _PlDanmakuState extends State<PlDanmaku> {
|
|||||||
enableShowDanmaku =
|
enableShowDanmaku =
|
||||||
setting.get(SettingBoxKey.enableShowDanmaku, defaultValue: false);
|
setting.get(SettingBoxKey.enableShowDanmaku, defaultValue: false);
|
||||||
_plDanmakuController =
|
_plDanmakuController =
|
||||||
PlDanmakuController(widget.cid);
|
PlDanmakuController(widget.cid, widget.playerController);
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
playerController = widget.playerController;
|
playerController = widget.playerController;
|
||||||
|
_plDanmakuController.videoDuration = playerController.duration.value;
|
||||||
if (enableShowDanmaku || playerController.isOpenDanmu.value) {
|
if (enableShowDanmaku || playerController.isOpenDanmu.value) {
|
||||||
_plDanmakuController.initiate(
|
_plDanmakuController
|
||||||
playerController.duration.value.inMilliseconds,
|
..calcSegment()
|
||||||
playerController.position.value.inMilliseconds
|
..queryDanmaku();
|
||||||
);
|
|
||||||
}
|
}
|
||||||
playerController
|
playerController
|
||||||
..addStatusLister(playerListener)
|
..addStatusLister(playerListener)
|
||||||
..addPositionListener(videoPositionListen);
|
..addPositionListener(videoPositionListen);
|
||||||
}
|
}
|
||||||
playerController.isOpenDanmu.listen((p0) {
|
playerController.isOpenDanmu.listen((p0) {
|
||||||
if (p0 && !_plDanmakuController.initiated) {
|
if (p0) {
|
||||||
_plDanmakuController.initiate(
|
if (_plDanmakuController.dmSegList.isEmpty) {
|
||||||
playerController.duration.value.inMilliseconds,
|
_plDanmakuController
|
||||||
playerController.position.value.inMilliseconds
|
..calcSegment()
|
||||||
);
|
..queryDanmaku();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
blockTypes = playerController.blockTypes;
|
blockTypes = playerController.blockTypes;
|
||||||
showArea = playerController.showArea;
|
showArea = playerController.showArea;
|
||||||
opacityVal = playerController.opacityVal;
|
opacityVal = playerController.opacityVal;
|
||||||
fontSizeVal = playerController.fontSizeVal;
|
fontSizeVal = playerController.fontSizeVal;
|
||||||
danmakuDurationVal = playerController.danmakuDurationVal;
|
danmakuSpeedVal = playerController.danmakuSpeedVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 播放器状态监听
|
// 播放器状态监听
|
||||||
@ -83,32 +81,54 @@ class _PlDanmakuState extends State<PlDanmaku> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void videoPositionListen(Duration position) {
|
void videoPositionListen(Duration position) {
|
||||||
|
if (!danmuPlayStatus) {
|
||||||
|
_controller!.onResume();
|
||||||
|
danmuPlayStatus = true;
|
||||||
|
}
|
||||||
|
PlDanmakuController ctr = _plDanmakuController;
|
||||||
|
int currentPosition = position.inMilliseconds;
|
||||||
|
blockTypes = playerController.blockTypes;
|
||||||
|
|
||||||
if (!playerController.isOpenDanmu.value) {
|
if (!playerController.isOpenDanmu.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int currentPosition = position.inMilliseconds;
|
// 超出分段数返回
|
||||||
currentPosition -= currentPosition % 100;//取整百的毫秒数
|
if (ctr.currentSegIndex >= ctr.dmSegList.length) {
|
||||||
|
|
||||||
if (currentPosition == latestAddedPosition) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
latestAddedPosition = currentPosition;
|
if (ctr.dmSegList.isEmpty ||
|
||||||
|
ctr.dmSegList[ctr.currentSegIndex].elems.isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 超出当前分段的弹幕总数返回
|
||||||
|
if (ctr.currentDmIndex >= ctr.dmSegList[ctr.currentSegIndex].elems.length) {
|
||||||
|
ctr.currentDmIndex = 0;
|
||||||
|
ctr.currentSegIndex++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var element = ctr.dmSegList[ctr.currentSegIndex].elems[ctr.currentDmIndex];
|
||||||
|
var delta = currentPosition - element.progress;
|
||||||
|
|
||||||
List<DanmakuElem>? currentDanmakuList =
|
if (delta >= 0 && delta < 200) {
|
||||||
_plDanmakuController.getCurrentDanmaku(currentPosition);
|
// 屏蔽彩色弹幕
|
||||||
|
if (blockTypes.contains(6) ? element.color == 16777215 : true) {
|
||||||
if (currentDanmakuList != null) {
|
_controller!.addItems([
|
||||||
Color? defaultColor = playerController.blockTypes.contains(6) ?
|
DanmakuItem(
|
||||||
DmUtils.decimalToColor(16777215) : null;
|
element.content,
|
||||||
|
color: DmUtils.decimalToColor(element.color),
|
||||||
_controller!.addItems(
|
time: element.progress,
|
||||||
currentDanmakuList.map((e) => DanmakuItem(
|
type: DmUtils.getPosition(element.mode),
|
||||||
e.content,
|
)
|
||||||
color: defaultColor ?? DmUtils.decimalToColor(e.color),
|
]);
|
||||||
time: e.progress,
|
}
|
||||||
type: DmUtils.getPosition(e.mode),
|
ctr.currentDmIndex++;
|
||||||
)).toList()
|
} else {
|
||||||
);
|
if (!playerController.isOpenDanmu.value) {
|
||||||
|
_controller!.pause();
|
||||||
|
danmuPlayStatus = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctr.findClosestPositionIndex(position.inMilliseconds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,8 +140,6 @@ class _PlDanmakuState extends State<PlDanmaku> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return LayoutBuilder(builder: (context, box) {
|
|
||||||
// double initDuration = box.maxWidth / 12;
|
|
||||||
return Obx(
|
return Obx(
|
||||||
() => AnimatedOpacity(
|
() => AnimatedOpacity(
|
||||||
opacity: playerController.isOpenDanmu.value ? 1 : 0,
|
opacity: playerController.isOpenDanmu.value ? 1 : 0,
|
||||||
@ -134,17 +152,11 @@ class _PlDanmakuState extends State<PlDanmaku> {
|
|||||||
fontSize: 15 * fontSizeVal,
|
fontSize: 15 * fontSizeVal,
|
||||||
area: showArea,
|
area: showArea,
|
||||||
opacity: opacityVal,
|
opacity: opacityVal,
|
||||||
hideTop: blockTypes.contains(5),
|
duration: danmakuSpeedVal * widget.playerController.playbackSpeed,
|
||||||
hideScroll: blockTypes.contains(2),
|
|
||||||
hideBottom: blockTypes.contains(4),
|
|
||||||
duration: danmakuDurationVal / widget.playerController.playbackSpeed,
|
|
||||||
// initDuration /
|
|
||||||
// (danmakuSpeedVal * widget.playerController.playbackSpeed),
|
|
||||||
),
|
),
|
||||||
statusChanged: (isPlaying) {},
|
statusChanged: (isPlaying) {},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -149,30 +149,10 @@ class DynamicsController extends GetxController {
|
|||||||
case 'DYNAMIC_TYPE_ARTICLE':
|
case 'DYNAMIC_TYPE_ARTICLE':
|
||||||
String title = item.modules.moduleDynamic.major.opus.title;
|
String title = item.modules.moduleDynamic.major.opus.title;
|
||||||
String url = item.modules.moduleDynamic.major.opus.jumpUrl;
|
String url = item.modules.moduleDynamic.major.opus.jumpUrl;
|
||||||
if (url.contains('opus') || url.contains('read')) {
|
|
||||||
RegExp digitRegExp = RegExp(r'\d+');
|
|
||||||
Iterable<Match> matches = digitRegExp.allMatches(url);
|
|
||||||
String number = matches.first.group(0)!;
|
|
||||||
if (url.contains('read')) {
|
|
||||||
number = 'cv$number';
|
|
||||||
}
|
|
||||||
Get.toNamed('/htmlRender', parameters: {
|
|
||||||
'url': url.startsWith('//') ? url.split('//').last : url,
|
|
||||||
'title': title,
|
|
||||||
'id': number,
|
|
||||||
'dynamicType': url.split('//').last.split('/')[1]
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Get.toNamed(
|
Get.toNamed(
|
||||||
'/webview',
|
'/webview',
|
||||||
parameters: {
|
parameters: {'url': 'https:$url', 'type': 'note', 'pageTitle': title},
|
||||||
'url': 'https:$url',
|
|
||||||
'type': 'note',
|
|
||||||
'pageTitle': title
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'DYNAMIC_TYPE_PGC':
|
case 'DYNAMIC_TYPE_PGC':
|
||||||
print('番剧');
|
print('番剧');
|
||||||
@ -234,7 +214,7 @@ class DynamicsController extends GetxController {
|
|||||||
arguments: {
|
arguments: {
|
||||||
'pic': pic,
|
'pic': pic,
|
||||||
'heroTag': heroTag,
|
'heroTag': heroTag,
|
||||||
'videoType': SearchType.media_bangumi,
|
// 'videoType': SearchType.media_bangumi,
|
||||||
'bangumiItem': res['data'],
|
'bangumiItem': res['data'],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
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/http/reply.dart';
|
import 'package:pilipala/http/reply.dart';
|
||||||
@ -18,7 +17,6 @@ class DynamicDetailController extends GetxController {
|
|||||||
RxString noMore = ''.obs;
|
RxString noMore = ''.obs;
|
||||||
RxList<ReplyItemModel> replyList = [ReplyItemModel()].obs;
|
RxList<ReplyItemModel> replyList = [ReplyItemModel()].obs;
|
||||||
RxInt acount = 0.obs;
|
RxInt acount = 0.obs;
|
||||||
final ScrollController scrollController = ScrollController();
|
|
||||||
|
|
||||||
ReplySortType _sortType = ReplySortType.time;
|
ReplySortType _sortType = ReplySortType.time;
|
||||||
RxString sortTypeTitle = ReplySortType.time.titles.obs;
|
RxString sortTypeTitle = ReplySortType.time.titles.obs;
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:easy_debounce/easy_throttle.dart';
|
import 'package:easy_debounce/easy_throttle.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/common/skeleton/video_reply.dart';
|
import 'package:pilipala/common/skeleton/video_reply.dart';
|
||||||
import 'package:pilipala/common/widgets/http_error.dart';
|
import 'package:pilipala/common/widgets/http_error.dart';
|
||||||
@ -10,10 +9,7 @@ import 'package:pilipala/models/common/reply_type.dart';
|
|||||||
import 'package:pilipala/pages/dynamics/deatil/index.dart';
|
import 'package:pilipala/pages/dynamics/deatil/index.dart';
|
||||||
import 'package:pilipala/pages/dynamics/widgets/author_panel.dart';
|
import 'package:pilipala/pages/dynamics/widgets/author_panel.dart';
|
||||||
import 'package:pilipala/pages/video/detail/reply/widgets/reply_item.dart';
|
import 'package:pilipala/pages/video/detail/reply/widgets/reply_item.dart';
|
||||||
import 'package:pilipala/pages/video/detail/replyNew/index.dart';
|
|
||||||
import 'package:pilipala/pages/video/detail/replyReply/index.dart';
|
import 'package:pilipala/pages/video/detail/replyReply/index.dart';
|
||||||
import 'package:pilipala/utils/feed_back.dart';
|
|
||||||
import 'package:pilipala/utils/id_utils.dart';
|
|
||||||
|
|
||||||
import '../widgets/dynamic_panel.dart';
|
import '../widgets/dynamic_panel.dart';
|
||||||
|
|
||||||
@ -25,18 +21,15 @@ class DynamicDetailPage extends StatefulWidget {
|
|||||||
State<DynamicDetailPage> createState() => _DynamicDetailPageState();
|
State<DynamicDetailPage> createState() => _DynamicDetailPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DynamicDetailPageState extends State<DynamicDetailPage>
|
class _DynamicDetailPageState extends State<DynamicDetailPage> {
|
||||||
with TickerProviderStateMixin {
|
late DynamicDetailController? _dynamicDetailController;
|
||||||
late DynamicDetailController _dynamicDetailController;
|
|
||||||
late AnimationController fabAnimationCtr;
|
|
||||||
Future? _futureBuilderFuture;
|
Future? _futureBuilderFuture;
|
||||||
late StreamController<bool> titleStreamC; // appBar title
|
late StreamController<bool> titleStreamC; // appBar title
|
||||||
late ScrollController scrollController;
|
final ScrollController scrollController = ScrollController();
|
||||||
bool _visibleTitle = false;
|
bool _visibleTitle = false;
|
||||||
String? action;
|
String? action;
|
||||||
// 回复类型
|
// 回复类型
|
||||||
late int type;
|
late int type;
|
||||||
bool _isFabVisible = true;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -57,30 +50,37 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
}
|
}
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
int commentType = 11;
|
int commentType = Get.arguments['item'].basic!['comment_type'] ?? 11;
|
||||||
try {
|
|
||||||
commentType = Get.arguments['item'].basic!['comment_type'];
|
|
||||||
} catch (_) {}
|
|
||||||
type = (commentType == 0) ? 11 : commentType;
|
type = (commentType == 0) ? 11 : commentType;
|
||||||
|
|
||||||
action =
|
action =
|
||||||
Get.arguments.containsKey('action') ? Get.arguments['action'] : null;
|
Get.arguments.containsKey('action') ? Get.arguments['action'] : null;
|
||||||
_dynamicDetailController =
|
_dynamicDetailController =
|
||||||
Get.put(DynamicDetailController(oid, type), tag: oid.toString());
|
Get.put(DynamicDetailController(oid, type), tag: oid.toString());
|
||||||
_futureBuilderFuture = _dynamicDetailController.queryReplyList();
|
_futureBuilderFuture = _dynamicDetailController!.queryReplyList();
|
||||||
titleStreamC = StreamController<bool>();
|
titleStreamC = StreamController<bool>();
|
||||||
|
scrollController.addListener(_listen);
|
||||||
if (action == 'comment') {
|
if (action == 'comment') {
|
||||||
_visibleTitle = true;
|
_visibleTitle = true;
|
||||||
titleStreamC.add(true);
|
titleStreamC.add(true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fabAnimationCtr = AnimationController(
|
void _listen() async {
|
||||||
vsync: this,
|
if (scrollController.position.pixels >=
|
||||||
duration: const Duration(milliseconds: 300),
|
scrollController.position.maxScrollExtent - 300) {
|
||||||
);
|
EasyThrottle.throttle('replylist', const Duration(seconds: 2), () {
|
||||||
fabAnimationCtr.forward();
|
_dynamicDetailController!.queryReplyList(reqType: 'onLoad');
|
||||||
// 滚动事件监听
|
});
|
||||||
scrollListener();
|
}
|
||||||
|
|
||||||
|
if (scrollController.offset > 55 && !_visibleTitle) {
|
||||||
|
_visibleTitle = true;
|
||||||
|
titleStreamC.add(true);
|
||||||
|
} else if (scrollController.offset <= 55 && _visibleTitle) {
|
||||||
|
_visibleTitle = false;
|
||||||
|
titleStreamC.add(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void replyReply(replyItem) {
|
void replyReply(replyItem) {
|
||||||
@ -107,58 +107,9 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void scrollListener() {
|
|
||||||
scrollController = _dynamicDetailController.scrollController;
|
|
||||||
scrollController.addListener(
|
|
||||||
() {
|
|
||||||
// 分页加载
|
|
||||||
if (scrollController.position.pixels >=
|
|
||||||
scrollController.position.maxScrollExtent - 300) {
|
|
||||||
EasyThrottle.throttle('replylist', const Duration(seconds: 2), () {
|
|
||||||
_dynamicDetailController.queryReplyList(reqType: 'onLoad');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 标题
|
|
||||||
if (scrollController.offset > 55 && !_visibleTitle) {
|
|
||||||
_visibleTitle = true;
|
|
||||||
titleStreamC.add(true);
|
|
||||||
} else if (scrollController.offset <= 55 && _visibleTitle) {
|
|
||||||
_visibleTitle = false;
|
|
||||||
titleStreamC.add(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// fab按钮
|
|
||||||
final ScrollDirection direction =
|
|
||||||
scrollController.position.userScrollDirection;
|
|
||||||
if (direction == ScrollDirection.forward) {
|
|
||||||
_showFab();
|
|
||||||
} else if (direction == ScrollDirection.reverse) {
|
|
||||||
_hideFab();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _showFab() {
|
|
||||||
if (!_isFabVisible) {
|
|
||||||
_isFabVisible = true;
|
|
||||||
fabAnimationCtr.forward();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _hideFab() {
|
|
||||||
if (_isFabVisible) {
|
|
||||||
_isFabVisible = false;
|
|
||||||
fabAnimationCtr.reverse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
scrollController.removeListener(() {});
|
scrollController.removeListener(() {});
|
||||||
fabAnimationCtr.dispose();
|
|
||||||
scrollController.dispose();
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +128,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
return AnimatedOpacity(
|
return AnimatedOpacity(
|
||||||
opacity: snapshot.data ? 1 : 0,
|
opacity: snapshot.data ? 1 : 0,
|
||||||
duration: const Duration(milliseconds: 300),
|
duration: const Duration(milliseconds: 300),
|
||||||
child: AuthorPanel(item: _dynamicDetailController.item),
|
child: author(_dynamicDetailController!.item, context),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -185,17 +136,15 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
),
|
),
|
||||||
body: RefreshIndicator(
|
body: RefreshIndicator(
|
||||||
onRefresh: () async {
|
onRefresh: () async {
|
||||||
await _dynamicDetailController.queryReplyList();
|
await _dynamicDetailController!.queryReplyList();
|
||||||
},
|
},
|
||||||
child: Stack(
|
child: CustomScrollView(
|
||||||
children: [
|
|
||||||
CustomScrollView(
|
|
||||||
controller: scrollController,
|
controller: scrollController,
|
||||||
slivers: [
|
slivers: [
|
||||||
if (action != 'comment')
|
if (action != 'comment')
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: DynamicPanel(
|
child: DynamicPanel(
|
||||||
item: _dynamicDetailController.item,
|
item: _dynamicDetailController!.item,
|
||||||
source: 'detail',
|
source: 'detail',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -207,9 +156,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
border: Border(
|
border: Border(
|
||||||
top: BorderSide(
|
top: BorderSide(
|
||||||
width: 0.6,
|
width: 0.6,
|
||||||
color: Theme.of(context)
|
color: Theme.of(context).dividerColor.withOpacity(0.05),
|
||||||
.dividerColor
|
|
||||||
.withOpacity(0.05),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -226,9 +173,9 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
scale: animation, child: child);
|
scale: animation, child: child);
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
'${_dynamicDetailController.acount.value}',
|
'${_dynamicDetailController!.acount.value}',
|
||||||
key: ValueKey<int>(
|
key: ValueKey<int>(
|
||||||
_dynamicDetailController.acount.value),
|
_dynamicDetailController!.acount.value),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -238,11 +185,10 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
height: 35,
|
height: 35,
|
||||||
child: TextButton.icon(
|
child: TextButton.icon(
|
||||||
onPressed: () =>
|
onPressed: () =>
|
||||||
_dynamicDetailController.queryBySort(),
|
_dynamicDetailController!.queryBySort(),
|
||||||
icon: const Icon(Icons.sort, size: 16),
|
icon: const Icon(Icons.sort, size: 16),
|
||||||
label: Obx(() => Text(
|
label: Obx(() => Text(
|
||||||
_dynamicDetailController
|
_dynamicDetailController!.sortTypeLabel.value,
|
||||||
.sortTypeLabel.value,
|
|
||||||
style: const TextStyle(fontSize: 13),
|
style: const TextStyle(fontSize: 13),
|
||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
@ -261,11 +207,11 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
if (snapshot.data['status']) {
|
if (snapshot.data['status']) {
|
||||||
// 请求成功
|
// 请求成功
|
||||||
return Obx(
|
return Obx(
|
||||||
() => _dynamicDetailController.replyList.isEmpty &&
|
() => _dynamicDetailController!.replyList.isEmpty &&
|
||||||
_dynamicDetailController.isLoadingMore
|
_dynamicDetailController!.isLoadingMore
|
||||||
? SliverList(
|
? SliverList(
|
||||||
delegate: SliverChildBuilderDelegate(
|
delegate:
|
||||||
(context, index) {
|
SliverChildBuilderDelegate((context, index) {
|
||||||
return const VideoReplySkeleton();
|
return const VideoReplySkeleton();
|
||||||
}, childCount: 8),
|
}, childCount: 8),
|
||||||
)
|
)
|
||||||
@ -273,7 +219,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
delegate: SliverChildBuilderDelegate(
|
delegate: SliverChildBuilderDelegate(
|
||||||
(context, index) {
|
(context, index) {
|
||||||
if (index ==
|
if (index ==
|
||||||
_dynamicDetailController
|
_dynamicDetailController!
|
||||||
.replyList.length) {
|
.replyList.length) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
@ -287,7 +233,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
child: Center(
|
child: Center(
|
||||||
child: Obx(
|
child: Obx(
|
||||||
() => Text(
|
() => Text(
|
||||||
_dynamicDetailController
|
_dynamicDetailController!
|
||||||
.noMore.value,
|
.noMore.value,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
@ -301,7 +247,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return ReplyItem(
|
return ReplyItem(
|
||||||
replyItem: _dynamicDetailController
|
replyItem: _dynamicDetailController!
|
||||||
.replyList[index],
|
.replyList[index],
|
||||||
showReplyRow: true,
|
showReplyRow: true,
|
||||||
replyLevel: '1',
|
replyLevel: '1',
|
||||||
@ -309,15 +255,15 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
replyReply(replyItem),
|
replyReply(replyItem),
|
||||||
replyType: ReplyType.values[type],
|
replyType: ReplyType.values[type],
|
||||||
addReply: (replyItem) {
|
addReply: (replyItem) {
|
||||||
_dynamicDetailController
|
_dynamicDetailController!
|
||||||
.replyList[index].replies!
|
.replyList[index].replies!
|
||||||
.add(replyItem);
|
.add(replyItem);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
childCount: _dynamicDetailController
|
childCount:
|
||||||
.replyList.length +
|
_dynamicDetailController!.replyList.length +
|
||||||
1,
|
1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -341,52 +287,6 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
|
|||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Positioned(
|
|
||||||
bottom: MediaQuery.of(context).padding.bottom + 14,
|
|
||||||
right: 14,
|
|
||||||
child: SlideTransition(
|
|
||||||
position: Tween<Offset>(
|
|
||||||
begin: const Offset(0, 2),
|
|
||||||
end: const Offset(0, 0),
|
|
||||||
).animate(CurvedAnimation(
|
|
||||||
parent: fabAnimationCtr,
|
|
||||||
curve: Curves.easeInOut,
|
|
||||||
)),
|
|
||||||
child: FloatingActionButton(
|
|
||||||
heroTag: null,
|
|
||||||
onPressed: () {
|
|
||||||
feedBack();
|
|
||||||
showModalBottomSheet(
|
|
||||||
context: context,
|
|
||||||
isScrollControlled: true,
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return VideoReplyNewDialog(
|
|
||||||
oid: _dynamicDetailController.oid ??
|
|
||||||
IdUtils.bv2av(Get.parameters['bvid']!),
|
|
||||||
root: 0,
|
|
||||||
parent: 0,
|
|
||||||
replyType: ReplyType.values[type],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
).then(
|
|
||||||
(value) => {
|
|
||||||
// 完成评论,数据添加
|
|
||||||
if (value != null && value['data'] != null)
|
|
||||||
{
|
|
||||||
_dynamicDetailController.replyList
|
|
||||||
.add(value['data']),
|
|
||||||
_dynamicDetailController.acount.value++
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
tooltip: '评论动态',
|
|
||||||
child: const Icon(Icons.reply),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -231,15 +231,6 @@ class _DynamicsPageState extends State<DynamicsPage>
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: Container(
|
|
||||||
height: 6,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.onInverseSurface
|
|
||||||
.withOpacity(0.5),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
FutureBuilder(
|
FutureBuilder(
|
||||||
future: _futureBuilderFuture,
|
future: _futureBuilderFuture,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
|
|||||||
@ -23,14 +23,7 @@ class ActionPanel extends StatefulWidget {
|
|||||||
class _ActionPanelState extends State<ActionPanel> {
|
class _ActionPanelState extends State<ActionPanel> {
|
||||||
final DynamicsController _dynamicsController = Get.put(DynamicsController());
|
final DynamicsController _dynamicsController = Get.put(DynamicsController());
|
||||||
late ModuleStatModel stat;
|
late ModuleStatModel stat;
|
||||||
bool isProcessing = false;
|
|
||||||
void Function()? handleState(Future Function() action) {
|
|
||||||
return isProcessing ? null : () async {
|
|
||||||
setState(() => isProcessing = true);
|
|
||||||
await action();
|
|
||||||
setState(() => isProcessing = false);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@ -38,7 +31,7 @@ class _ActionPanelState extends State<ActionPanel> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 动态点赞
|
// 动态点赞
|
||||||
Future onLikeDynamic() async {
|
onLikeDynamic() async {
|
||||||
feedBack();
|
feedBack();
|
||||||
var item = widget.item!;
|
var item = widget.item!;
|
||||||
String dynamicId = item.idStr!;
|
String dynamicId = item.idStr!;
|
||||||
@ -108,7 +101,7 @@ class _ActionPanelState extends State<ActionPanel> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
flex: 1,
|
flex: 1,
|
||||||
child: TextButton.icon(
|
child: TextButton.icon(
|
||||||
onPressed: handleState(onLikeDynamic),
|
onPressed: () => onLikeDynamic(),
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
stat.like!.status!
|
stat.like!.status!
|
||||||
? FontAwesomeIcons.solidThumbsUp
|
? FontAwesomeIcons.solidThumbsUp
|
||||||
|
|||||||
@ -1,8 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
import 'package:pilipala/http/search.dart';
|
|
||||||
|
|
||||||
/// TODO 点击跳转
|
/// TODO 点击跳转
|
||||||
Widget addWidget(item, context, type, {floor = 1}) {
|
Widget addWidget(item, context, type, {floor = 1}) {
|
||||||
@ -22,27 +19,8 @@ Widget addWidget(item, context, type, {floor = 1}) {
|
|||||||
: Theme.of(context).colorScheme.background;
|
: Theme.of(context).colorScheme.background;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'ADDITIONAL_TYPE_UGC':
|
case 'ADDITIONAL_TYPE_UGC':
|
||||||
// 转发的投稿
|
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () async {
|
onTap: () {},
|
||||||
String text = dynamicProperty[type].jumpUrl;
|
|
||||||
RegExp bvRegex = RegExp(r'BV[0-9A-Za-z]{10}', caseSensitive: false);
|
|
||||||
Iterable<Match> matches = bvRegex.allMatches(text);
|
|
||||||
if (matches.isNotEmpty) {
|
|
||||||
Match match = matches.first;
|
|
||||||
String bvid = match.group(0)!;
|
|
||||||
String cover = dynamicProperty[type].cover;
|
|
||||||
try {
|
|
||||||
int cid = await SearchHttp.ab2c(bvid: bvid);
|
|
||||||
Get.toNamed('/video?bvid=$bvid&cid=$cid',
|
|
||||||
arguments: {'pic': cover, 'heroTag': bvid});
|
|
||||||
} catch (err) {
|
|
||||||
SmartDialog.showToast(err.toString());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
print("No match found.");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: Container(
|
child: Container(
|
||||||
padding:
|
padding:
|
||||||
const EdgeInsets.only(left: 12, top: 8, right: 12, bottom: 8),
|
const EdgeInsets.only(left: 12, top: 8, right: 12, bottom: 8),
|
||||||
@ -83,7 +61,6 @@ Widget addWidget(item, context, type, {floor = 1}) {
|
|||||||
);
|
);
|
||||||
case 'ADDITIONAL_TYPE_RESERVE':
|
case 'ADDITIONAL_TYPE_RESERVE':
|
||||||
return dynamicProperty[type].state != -1
|
return dynamicProperty[type].state != -1
|
||||||
? dynamicProperty[type].title != null
|
|
||||||
? Padding(
|
? Padding(
|
||||||
padding: const EdgeInsets.only(top: 8),
|
padding: const EdgeInsets.only(top: 8),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
@ -111,15 +88,9 @@ Widget addWidget(item, context, type, {floor = 1}) {
|
|||||||
.labelMedium!
|
.labelMedium!
|
||||||
.fontSize),
|
.fontSize),
|
||||||
children: [
|
children: [
|
||||||
if (dynamicProperty[type].desc1 != null)
|
TextSpan(text: dynamicProperty[type].desc1['text']),
|
||||||
TextSpan(
|
|
||||||
text:
|
|
||||||
dynamicProperty[type].desc1['text']),
|
|
||||||
const TextSpan(text: ' '),
|
const TextSpan(text: ' '),
|
||||||
if (dynamicProperty[type].desc2 != null)
|
TextSpan(text: dynamicProperty[type].desc2['text']),
|
||||||
TextSpan(
|
|
||||||
text:
|
|
||||||
dynamicProperty[type].desc2['text']),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -129,65 +100,62 @@ Widget addWidget(item, context, type, {floor = 1}) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: const SizedBox()
|
|
||||||
: const SizedBox();
|
: const SizedBox();
|
||||||
case 'ADDITIONAL_TYPE_GOODS':
|
case 'ADDITIONAL_TYPE_GOODS':
|
||||||
// 商品
|
return Padding(
|
||||||
return const SizedBox();
|
padding: const EdgeInsets.only(top: 6),
|
||||||
// return Padding(
|
child: InkWell(
|
||||||
// padding: const EdgeInsets.only(top: 6),
|
onTap: () {},
|
||||||
// child: InkWell(
|
child: Container(
|
||||||
// onTap: () {},
|
padding:
|
||||||
// child: Container(
|
const EdgeInsets.only(left: 12, top: 8, right: 12, bottom: 8),
|
||||||
// padding:
|
decoration: BoxDecoration(
|
||||||
// const EdgeInsets.only(left: 12, top: 8, right: 12, bottom: 8),
|
color: bgColor,
|
||||||
// decoration: BoxDecoration(
|
borderRadius: const BorderRadius.all(Radius.circular(6)),
|
||||||
// color: bgColor,
|
),
|
||||||
// borderRadius: const BorderRadius.all(Radius.circular(6)),
|
child: Row(
|
||||||
// ),
|
children: [
|
||||||
// child: Row(
|
NetworkImgLayer(
|
||||||
// children: [
|
width: 75,
|
||||||
// NetworkImgLayer(
|
height: 75,
|
||||||
// width: 75,
|
src: dynamicProperty[type].items.first.cover,
|
||||||
// height: 75,
|
),
|
||||||
// src: dynamicProperty[type].items.first.cover,
|
const SizedBox(width: 10),
|
||||||
// ),
|
Expanded(
|
||||||
// const SizedBox(width: 10),
|
child: Column(
|
||||||
// Expanded(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
// child: Column(
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
children: [
|
||||||
// mainAxisAlignment: MainAxisAlignment.start,
|
Text(
|
||||||
// children: [
|
dynamicProperty[type].items.first.name,
|
||||||
// Text(
|
maxLines: 1,
|
||||||
// dynamicProperty[type].items.first.name,
|
overflow: TextOverflow.ellipsis,
|
||||||
// maxLines: 1,
|
),
|
||||||
// overflow: TextOverflow.ellipsis,
|
Text(
|
||||||
// ),
|
dynamicProperty[type].items.first.brief,
|
||||||
// Text(
|
maxLines: 1,
|
||||||
// dynamicProperty[type].items.first.brief,
|
style: TextStyle(
|
||||||
// maxLines: 1,
|
color: Theme.of(context).colorScheme.outline,
|
||||||
// style: TextStyle(
|
fontSize: Theme.of(context)
|
||||||
// color: Theme.of(context).colorScheme.outline,
|
.textTheme
|
||||||
// fontSize: Theme.of(context)
|
.labelMedium!
|
||||||
// .textTheme
|
.fontSize,
|
||||||
// .labelMedium!
|
),
|
||||||
// .fontSize,
|
),
|
||||||
// ),
|
const SizedBox(height: 2),
|
||||||
// ),
|
Text(
|
||||||
// const SizedBox(height: 2),
|
dynamicProperty[type].items.first.price,
|
||||||
// Text(
|
style: TextStyle(
|
||||||
// dynamicProperty[type].items.first.price,
|
color: Theme.of(context).colorScheme.primary,
|
||||||
// style: TextStyle(
|
),
|
||||||
// color: Theme.of(context).colorScheme.primary,
|
),
|
||||||
// ),
|
],
|
||||||
// ),
|
),
|
||||||
// ],
|
),
|
||||||
// ),
|
],
|
||||||
// ),
|
),
|
||||||
// ],
|
),
|
||||||
// ),
|
));
|
||||||
// ),
|
|
||||||
// ),);
|
|
||||||
case 'ADDITIONAL_TYPE_MATCH':
|
case 'ADDITIONAL_TYPE_MATCH':
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
case 'ADDITIONAL_TYPE_COMMON':
|
case 'ADDITIONAL_TYPE_COMMON':
|
||||||
|
|||||||
@ -1,26 +1,15 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
import 'package:pilipala/http/user.dart';
|
|
||||||
import 'package:pilipala/utils/feed_back.dart';
|
import 'package:pilipala/utils/feed_back.dart';
|
||||||
import 'package:pilipala/utils/utils.dart';
|
import 'package:pilipala/utils/utils.dart';
|
||||||
|
|
||||||
class AuthorPanel extends StatelessWidget {
|
Widget author(item, context) {
|
||||||
final dynamic item;
|
|
||||||
const AuthorPanel({super.key, required this.item});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
String heroTag = Utils.makeHeroTag(item.modules.moduleAuthor.mid);
|
String heroTag = Utils.makeHeroTag(item.modules.moduleAuthor.mid);
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
// 番剧
|
|
||||||
if (item.modules.moduleAuthor.type == 'AUTHOR_TYPE_PGC') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
feedBack();
|
feedBack();
|
||||||
Get.toNamed(
|
Get.toNamed(
|
||||||
'/member?mid=${item.modules.moduleAuthor.mid}',
|
'/member?mid=${item.modules.moduleAuthor.mid}',
|
||||||
@ -71,93 +60,6 @@ class AuthorPanel extends StatelessWidget {
|
|||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const Spacer(),
|
|
||||||
if (item.type == 'DYNAMIC_TYPE_AV')
|
|
||||||
SizedBox(
|
|
||||||
width: 32,
|
|
||||||
height: 32,
|
|
||||||
child: IconButton(
|
|
||||||
style: ButtonStyle(
|
|
||||||
padding: MaterialStateProperty.all(EdgeInsets.zero),
|
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
showModalBottomSheet(
|
|
||||||
context: context,
|
|
||||||
useRootNavigator: true,
|
|
||||||
isScrollControlled: true,
|
|
||||||
builder: (context) {
|
|
||||||
return MorePanel(item: item);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.more_vert_outlined, size: 18),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
class MorePanel extends StatelessWidget {
|
|
||||||
final dynamic item;
|
|
||||||
const MorePanel({super.key, required this.item});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container(
|
|
||||||
padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom),
|
|
||||||
// clipBehavior: Clip.hardEdge,
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
InkWell(
|
|
||||||
onTap: () => Get.back(),
|
|
||||||
child: Container(
|
|
||||||
height: 35,
|
|
||||||
padding: const EdgeInsets.only(bottom: 2),
|
|
||||||
child: Center(
|
|
||||||
child: Container(
|
|
||||||
width: 32,
|
|
||||||
height: 3,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Theme.of(context).colorScheme.outline,
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(3))),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
onTap: () async {
|
|
||||||
try {
|
|
||||||
String bvid = item.modules.moduleDynamic.major.archive.bvid;
|
|
||||||
var res = await UserHttp.toViewLater(bvid: bvid);
|
|
||||||
SmartDialog.showToast(res['msg']);
|
|
||||||
Get.back();
|
|
||||||
} catch (err) {
|
|
||||||
SmartDialog.showToast('出错了:${err.toString()}');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
minLeadingWidth: 0,
|
|
||||||
// dense: true,
|
|
||||||
leading: const Icon(Icons.watch_later_outlined, size: 19),
|
|
||||||
title: Text(
|
|
||||||
'稍后再看',
|
|
||||||
style: Theme.of(context).textTheme.titleSmall,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const Divider(thickness: 0.1, height: 1),
|
|
||||||
ListTile(
|
|
||||||
onTap: () => Get.back(),
|
|
||||||
minLeadingWidth: 0,
|
|
||||||
dense: true,
|
|
||||||
title: Text(
|
|
||||||
'取消',
|
|
||||||
style: TextStyle(color: Theme.of(context).colorScheme.outline),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,165 +1,28 @@
|
|||||||
// 内容
|
// 内容
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
|
||||||
import 'package:pilipala/models/dynamics/result.dart';
|
|
||||||
import 'package:pilipala/pages/preview/index.dart';
|
|
||||||
|
|
||||||
import 'rich_node_panel.dart';
|
import 'rich_node_panel.dart';
|
||||||
|
|
||||||
// ignore: must_be_immutable
|
Widget content(item, context, source) {
|
||||||
class Content extends StatefulWidget {
|
|
||||||
dynamic item;
|
|
||||||
String? source;
|
|
||||||
Content({
|
|
||||||
super.key,
|
|
||||||
this.item,
|
|
||||||
this.source,
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<Content> createState() => _ContentState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ContentState extends State<Content> {
|
|
||||||
late bool hasPics;
|
|
||||||
List<OpusPicsModel> pics = [];
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
hasPics = widget.item.modules.moduleDynamic.major != null &&
|
|
||||||
widget.item.modules.moduleDynamic.major.opus != null &&
|
|
||||||
widget.item.modules.moduleDynamic.major.opus.pics.isNotEmpty;
|
|
||||||
if (hasPics) {
|
|
||||||
pics = widget.item.modules.moduleDynamic.major.opus.pics;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
InlineSpan picsNodes() {
|
|
||||||
List<InlineSpan> spanChilds = [];
|
|
||||||
int len = pics.length;
|
|
||||||
List<String> picList = [];
|
|
||||||
|
|
||||||
if (len == 1) {
|
|
||||||
OpusPicsModel pictureItem = pics.first;
|
|
||||||
picList.add(pictureItem.url!);
|
|
||||||
spanChilds.add(const TextSpan(text: '\n'));
|
|
||||||
spanChilds.add(
|
|
||||||
WidgetSpan(
|
|
||||||
child: LayoutBuilder(
|
|
||||||
builder: (context, BoxConstraints box) {
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
showDialog(
|
|
||||||
useSafeArea: false,
|
|
||||||
context: context,
|
|
||||||
builder: (context) {
|
|
||||||
return ImagePreview(initialPage: 0, imgList: picList);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 4),
|
|
||||||
child: NetworkImgLayer(
|
|
||||||
src: pictureItem.url,
|
|
||||||
width: box.maxWidth / 2,
|
|
||||||
height: box.maxWidth *
|
|
||||||
0.5 *
|
|
||||||
(pictureItem.height != null && pictureItem.width != null
|
|
||||||
? pictureItem.height! / pictureItem.width!
|
|
||||||
: 1),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (len > 1) {
|
|
||||||
List<Widget> list = [];
|
|
||||||
for (var i = 0; i < len; i++) {
|
|
||||||
picList.add(pics[i].url!);
|
|
||||||
list.add(
|
|
||||||
LayoutBuilder(
|
|
||||||
builder: (context, BoxConstraints box) {
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
showDialog(
|
|
||||||
useSafeArea: false,
|
|
||||||
context: context,
|
|
||||||
builder: (context) {
|
|
||||||
return ImagePreview(initialPage: i, imgList: picList);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: NetworkImgLayer(
|
|
||||||
src: pics[i].url,
|
|
||||||
width: box.maxWidth,
|
|
||||||
height: box.maxWidth,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
spanChilds.add(
|
|
||||||
WidgetSpan(
|
|
||||||
child: LayoutBuilder(
|
|
||||||
builder: (context, BoxConstraints box) {
|
|
||||||
double maxWidth = box.maxWidth;
|
|
||||||
double crossCount = len < 3 ? 2 : 3;
|
|
||||||
double height = maxWidth /
|
|
||||||
crossCount *
|
|
||||||
(len % crossCount == 0
|
|
||||||
? len ~/ crossCount
|
|
||||||
: len ~/ crossCount + 1) +
|
|
||||||
6;
|
|
||||||
return Container(
|
|
||||||
padding: const EdgeInsets.only(top: 6),
|
|
||||||
height: height,
|
|
||||||
child: GridView.count(
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
crossAxisCount: crossCount.toInt(),
|
|
||||||
mainAxisSpacing: 4.0,
|
|
||||||
crossAxisSpacing: 4.0,
|
|
||||||
childAspectRatio: 1,
|
|
||||||
children: list,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return TextSpan(
|
|
||||||
children: spanChilds,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
TextStyle authorStyle =
|
TextStyle authorStyle =
|
||||||
TextStyle(color: Theme.of(context).colorScheme.primary);
|
TextStyle(color: Theme.of(context).colorScheme.primary);
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
padding: const EdgeInsets.fromLTRB(12, 0, 12, 6),
|
padding: const EdgeInsets.fromLTRB(12, 0, 12, 6),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if (widget.item.modules.moduleDynamic.topic != null) ...[
|
if (item.modules.moduleDynamic.topic != null) ...[
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
child: Text(
|
child: Text(
|
||||||
'#${widget.item.modules.moduleDynamic.topic.name}',
|
'#${item.modules.moduleDynamic.topic.name}',
|
||||||
style: authorStyle,
|
style: authorStyle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
IgnorePointer(
|
IgnorePointer(
|
||||||
// 禁用SelectableRegion的触摸交互功能
|
// 禁用SelectableRegion的触摸交互功能
|
||||||
ignoring: widget.source == 'detail' ? false : true,
|
ignoring: source == 'detail' ? false : true,
|
||||||
child: SelectableRegion(
|
child: SelectableRegion(
|
||||||
magnifierConfiguration: const TextMagnifierConfiguration(),
|
magnifierConfiguration: const TextMagnifierConfiguration(),
|
||||||
focusNode: FocusNode(),
|
focusNode: FocusNode(),
|
||||||
@ -167,17 +30,13 @@ class _ContentState extends State<Content> {
|
|||||||
child: Text.rich(
|
child: Text.rich(
|
||||||
/// fix 默认20px高度
|
/// fix 默认20px高度
|
||||||
style: const TextStyle(height: 0),
|
style: const TextStyle(height: 0),
|
||||||
richNode(widget.item, context),
|
richNode(item, context),
|
||||||
maxLines: widget.source == 'detail' ? 999 : 3,
|
maxLines: source == 'detail' ? 999 : 3,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (hasPics) ...[
|
|
||||||
Text.rich(picsNodes()),
|
|
||||||
]
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@ -39,11 +39,11 @@ class DynamicPanel extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(12, 12, 12, 8),
|
padding: const EdgeInsets.fromLTRB(12, 12, 12, 8),
|
||||||
child: AuthorPanel(item: item),
|
child: author(item, context),
|
||||||
),
|
),
|
||||||
if (item!.modules!.moduleDynamic!.desc != null ||
|
if (item!.modules!.moduleDynamic!.desc != null ||
|
||||||
item!.modules!.moduleDynamic!.major != null)
|
item!.modules!.moduleDynamic!.major != null)
|
||||||
Content(item: item, source: source),
|
content(item, context, source),
|
||||||
forWard(item, context, _dynamicsController, source),
|
forWard(item, context, _dynamicsController, source),
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
if (source == null) ActionPanel(item: item),
|
if (source == null) ActionPanel(item: item),
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.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/pages/preview/index.dart';
|
||||||
|
|
||||||
// 富文本
|
// 富文本
|
||||||
InlineSpan richNode(item, context) {
|
InlineSpan richNode(item, context) {
|
||||||
@ -9,11 +11,13 @@ InlineSpan richNode(item, context) {
|
|||||||
TextStyle authorStyle =
|
TextStyle authorStyle =
|
||||||
TextStyle(color: Theme.of(context).colorScheme.primary);
|
TextStyle(color: Theme.of(context).colorScheme.primary);
|
||||||
List<InlineSpan> spanChilds = [];
|
List<InlineSpan> spanChilds = [];
|
||||||
|
String contentType = 'desc';
|
||||||
|
|
||||||
dynamic richTextNodes;
|
dynamic richTextNodes;
|
||||||
if (item.modules.moduleDynamic.desc != null) {
|
if (item.modules.moduleDynamic.desc != null) {
|
||||||
richTextNodes = item.modules.moduleDynamic.desc.richTextNodes;
|
richTextNodes = item.modules.moduleDynamic.desc.richTextNodes;
|
||||||
} else if (item.modules.moduleDynamic.major != null) {
|
} else if (item.modules.moduleDynamic.major != null) {
|
||||||
|
contentType = 'major';
|
||||||
// 动态页面 richTextNodes 层级可能与主页动态层级不同
|
// 动态页面 richTextNodes 层级可能与主页动态层级不同
|
||||||
richTextNodes =
|
richTextNodes =
|
||||||
item.modules.moduleDynamic.major.opus.summary.richTextNodes;
|
item.modules.moduleDynamic.major.opus.summary.richTextNodes;
|
||||||
@ -23,9 +27,8 @@ InlineSpan richNode(item, context) {
|
|||||||
} else {
|
} else {
|
||||||
for (var i in richTextNodes) {
|
for (var i in richTextNodes) {
|
||||||
/// fix 渲染专栏时内容会重复
|
/// fix 渲染专栏时内容会重复
|
||||||
// if (item.modules.moduleDynamic.major.opus.title == null &&
|
if (item.modules.moduleDynamic.major.opus.title == null &&
|
||||||
// i.type == 'RICH_TEXT_NODE_TYPE_TEXT') {
|
i.type == 'RICH_TEXT_NODE_TYPE_TEXT') {
|
||||||
if (i.type == 'RICH_TEXT_NODE_TYPE_TEXT') {
|
|
||||||
spanChilds.add(
|
spanChilds.add(
|
||||||
TextSpan(text: i.origText, style: const TextStyle(height: 1.65)));
|
TextSpan(text: i.origText, style: const TextStyle(height: 1.65)));
|
||||||
}
|
}
|
||||||
@ -106,7 +109,6 @@ InlineSpan richNode(item, context) {
|
|||||||
alignment: PlaceholderAlignment.middle,
|
alignment: PlaceholderAlignment.middle,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
try {
|
|
||||||
String dynamicId = item.basic['comment_id_str'];
|
String dynamicId = item.basic['comment_id_str'];
|
||||||
Get.toNamed(
|
Get.toNamed(
|
||||||
'/webview',
|
'/webview',
|
||||||
@ -117,7 +119,6 @@ InlineSpan richNode(item, context) {
|
|||||||
'pageTitle': '投票'
|
'pageTitle': '投票'
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} catch (_) {}
|
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
'投票:${i.text}',
|
'投票:${i.text}',
|
||||||
@ -192,107 +193,105 @@ InlineSpan richNode(item, context) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if (contentType == 'major' &&
|
if (contentType == 'major' &&
|
||||||
// item.modules.moduleDynamic.major.opus.pics.isNotEmpty) {
|
item.modules.moduleDynamic.major.opus.pics.isNotEmpty) {
|
||||||
// // 图片可能跟其他widget重复渲染
|
// 图片可能跟其他widget重复渲染
|
||||||
// List<OpusPicsModel> pics = item.modules.moduleDynamic.major.opus.pics;
|
List<OpusPicsModel> pics = item.modules.moduleDynamic.major.opus.pics;
|
||||||
// int len = pics.length;
|
int len = pics.length;
|
||||||
// List<String> picList = [];
|
List<String> picList = [];
|
||||||
|
|
||||||
// if (len == 1) {
|
if (len == 1) {
|
||||||
// OpusPicsModel pictureItem = pics.first;
|
OpusPicsModel pictureItem = pics.first;
|
||||||
// picList.add(pictureItem.url!);
|
picList.add(pictureItem.url!);
|
||||||
// spanChilds.add(const TextSpan(text: '\n'));
|
spanChilds.add(const TextSpan(text: '\n'));
|
||||||
// spanChilds.add(
|
spanChilds.add(
|
||||||
// WidgetSpan(
|
WidgetSpan(
|
||||||
// child: LayoutBuilder(
|
child: LayoutBuilder(
|
||||||
// builder: (context, BoxConstraints box) {
|
builder: (context, BoxConstraints box) {
|
||||||
// return GestureDetector(
|
return GestureDetector(
|
||||||
// onTap: () {
|
onTap: () {
|
||||||
// showDialog(
|
showDialog(
|
||||||
// useSafeArea: false,
|
useSafeArea: false,
|
||||||
// context: context,
|
context: context,
|
||||||
// builder: (context) {
|
builder: (context) {
|
||||||
// return ImagePreview(initialPage: 0, imgList: picList);
|
return ImagePreview(initialPage: 0, imgList: picList);
|
||||||
// },
|
},
|
||||||
// );
|
);
|
||||||
// },
|
},
|
||||||
// child: Padding(
|
child: Padding(
|
||||||
// padding: const EdgeInsets.only(top: 4),
|
padding: const EdgeInsets.only(top: 4),
|
||||||
// child: NetworkImgLayer(
|
child: NetworkImgLayer(
|
||||||
// src: pictureItem.url,
|
src: pictureItem.url,
|
||||||
// width: box.maxWidth / 2,
|
width: box.maxWidth / 2,
|
||||||
// height: box.maxWidth *
|
height: box.maxWidth *
|
||||||
// 0.5 *
|
0.5 *
|
||||||
// (pictureItem.height != null &&
|
pictureItem.height! /
|
||||||
// pictureItem.width != null
|
pictureItem.width!,
|
||||||
// ? pictureItem.height! / pictureItem.width!
|
),
|
||||||
// : 1),
|
),
|
||||||
// ),
|
);
|
||||||
// ),
|
},
|
||||||
// );
|
),
|
||||||
// },
|
),
|
||||||
// ),
|
);
|
||||||
// ),
|
}
|
||||||
// );
|
if (len > 1) {
|
||||||
// }
|
List<Widget> list = [];
|
||||||
// if (len > 1) {
|
for (var i = 0; i < len; i++) {
|
||||||
// List<Widget> list = [];
|
picList.add(pics[i].url!);
|
||||||
// for (var i = 0; i < len; i++) {
|
list.add(
|
||||||
// picList.add(pics[i].url!);
|
LayoutBuilder(
|
||||||
// list.add(
|
builder: (context, BoxConstraints box) {
|
||||||
// LayoutBuilder(
|
return GestureDetector(
|
||||||
// builder: (context, BoxConstraints box) {
|
onTap: () {
|
||||||
// return GestureDetector(
|
showDialog(
|
||||||
// onTap: () {
|
useSafeArea: false,
|
||||||
// showDialog(
|
context: context,
|
||||||
// useSafeArea: false,
|
builder: (context) {
|
||||||
// context: context,
|
return ImagePreview(initialPage: i, imgList: picList);
|
||||||
// builder: (context) {
|
},
|
||||||
// return ImagePreview(initialPage: i, imgList: picList);
|
);
|
||||||
// },
|
},
|
||||||
// );
|
child: NetworkImgLayer(
|
||||||
// },
|
src: pics[i].url,
|
||||||
// child: NetworkImgLayer(
|
width: box.maxWidth,
|
||||||
// src: pics[i].url,
|
height: box.maxWidth,
|
||||||
// width: box.maxWidth,
|
),
|
||||||
// height: box.maxWidth,
|
);
|
||||||
// ),
|
},
|
||||||
// );
|
),
|
||||||
// },
|
);
|
||||||
// ),
|
}
|
||||||
// );
|
spanChilds.add(
|
||||||
// }
|
WidgetSpan(
|
||||||
// spanChilds.add(
|
child: LayoutBuilder(
|
||||||
// WidgetSpan(
|
builder: (context, BoxConstraints box) {
|
||||||
// child: LayoutBuilder(
|
double maxWidth = box.maxWidth;
|
||||||
// builder: (context, BoxConstraints box) {
|
double crossCount = len < 3 ? 2 : 3;
|
||||||
// double maxWidth = box.maxWidth;
|
double height = maxWidth /
|
||||||
// double crossCount = len < 3 ? 2 : 3;
|
crossCount *
|
||||||
// double height = maxWidth /
|
(len % crossCount == 0
|
||||||
// crossCount *
|
? len ~/ crossCount
|
||||||
// (len % crossCount == 0
|
: len ~/ crossCount + 1) +
|
||||||
// ? len ~/ crossCount
|
6;
|
||||||
// : len ~/ crossCount + 1) +
|
return Container(
|
||||||
// 6;
|
padding: const EdgeInsets.only(top: 6),
|
||||||
// return Container(
|
height: height,
|
||||||
// padding: const EdgeInsets.only(top: 6),
|
child: GridView.count(
|
||||||
// height: height,
|
padding: EdgeInsets.zero,
|
||||||
// child: GridView.count(
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
// padding: EdgeInsets.zero,
|
crossAxisCount: crossCount.toInt(),
|
||||||
// physics: const NeverScrollableScrollPhysics(),
|
mainAxisSpacing: 4.0,
|
||||||
// crossAxisCount: crossCount.toInt(),
|
crossAxisSpacing: 4.0,
|
||||||
// mainAxisSpacing: 4.0,
|
childAspectRatio: 1,
|
||||||
// crossAxisSpacing: 4.0,
|
children: list,
|
||||||
// childAspectRatio: 1,
|
),
|
||||||
// children: list,
|
);
|
||||||
// ),
|
},
|
||||||
// );
|
),
|
||||||
// },
|
),
|
||||||
// ),
|
);
|
||||||
// ),
|
}
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// spanChilds.add(
|
// spanChilds.add(
|
||||||
// WidgetSpan(
|
// WidgetSpan(
|
||||||
// child: NetworkImgLayer(
|
// child: NetworkImgLayer(
|
||||||
@ -303,7 +302,7 @@ InlineSpan richNode(item, context) {
|
|||||||
// ),
|
// ),
|
||||||
// ),
|
// ),
|
||||||
// );
|
// );
|
||||||
// }
|
}
|
||||||
return TextSpan(
|
return TextSpan(
|
||||||
children: spanChilds,
|
children: spanChilds,
|
||||||
);
|
);
|
||||||
|
|||||||