Merge branch 'main' into feature-search
This commit is contained in:
@ -94,7 +94,7 @@ QQ频道: https://pd.qq.com/s/365esodk3
|
|||||||
- [x] 音质选择(视视频而定)
|
- [x] 音质选择(视视频而定)
|
||||||
- [x] 解码格式选择(视视频而定)
|
- [x] 解码格式选择(视视频而定)
|
||||||
- [x] 弹幕
|
- [x] 弹幕
|
||||||
- [ ] 字幕
|
- [x] 字幕
|
||||||
- [x] 记忆播放
|
- [x] 记忆播放
|
||||||
- [x] 视频比例:高度/宽度适应、填充、包含等
|
- [x] 视频比例:高度/宽度适应、填充、包含等
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = '1.7.10'
|
ext.kotlin_version = '1.9.0'
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
|||||||
1
assets/loading.json
Normal file
1
assets/loading.json
Normal file
File diff suppressed because one or more lines are too long
1
assets/trail_loading.json
Normal file
1
assets/trail_loading.json
Normal file
File diff suppressed because one or more lines are too long
@ -21,6 +21,6 @@
|
|||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>MinimumOSVersion</key>
|
<key>MinimumOSVersion</key>
|
||||||
<string>11.0</string>
|
<string>12.0</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@ -10,7 +10,6 @@ PODS:
|
|||||||
- connectivity_plus (0.0.1):
|
- connectivity_plus (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- ReachabilitySwift
|
|
||||||
- device_info_plus (0.0.1):
|
- device_info_plus (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- Flutter (1.0.0)
|
- Flutter (1.0.0)
|
||||||
@ -41,7 +40,6 @@ PODS:
|
|||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- permission_handler_apple (9.3.0):
|
- permission_handler_apple (9.3.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
- ReachabilitySwift (5.0.0)
|
|
||||||
- saver_gallery (0.0.1):
|
- saver_gallery (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- screen_brightness_ios (0.1.0):
|
- screen_brightness_ios (0.1.0):
|
||||||
@ -101,7 +99,6 @@ SPEC REPOS:
|
|||||||
trunk:
|
trunk:
|
||||||
- FMDB
|
- FMDB
|
||||||
- GT3Captcha-iOS
|
- GT3Captcha-iOS
|
||||||
- ReachabilitySwift
|
|
||||||
- Toast
|
- Toast
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
@ -167,9 +164,9 @@ SPEC CHECKSUMS:
|
|||||||
audio_service: f509d65da41b9521a61f1c404dd58651f265a567
|
audio_service: f509d65da41b9521a61f1c404dd58651f265a567
|
||||||
audio_session: 4f3e461722055d21515cf3261b64c973c062f345
|
audio_session: 4f3e461722055d21515cf3261b64c973c062f345
|
||||||
auto_orientation: 102ed811a5938d52c86520ddd7ecd3a126b5d39d
|
auto_orientation: 102ed811a5938d52c86520ddd7ecd3a126b5d39d
|
||||||
connectivity_plus: e2dad488011aeb593e219360e804c43cc1af5770
|
connectivity_plus: ddd7f30999e1faaef5967c23d5b6d503d10434db
|
||||||
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
|
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
|
||||||
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||||
flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83
|
flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83
|
||||||
flutter_volume_controller: e4d5832f08008180f76e30faf671ffd5a425e529
|
flutter_volume_controller: e4d5832f08008180f76e30faf671ffd5a425e529
|
||||||
fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265
|
fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265
|
||||||
@ -182,7 +179,6 @@ SPEC CHECKSUMS:
|
|||||||
package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
|
package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
|
||||||
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
|
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
|
||||||
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
|
||||||
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
|
|
||||||
saver_gallery: 2b4e584106fde2407ab51560f3851564963e6b78
|
saver_gallery: 2b4e584106fde2407ab51560f3851564963e6b78
|
||||||
screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625
|
screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625
|
||||||
share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5
|
share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5
|
||||||
@ -190,11 +186,11 @@ SPEC CHECKSUMS:
|
|||||||
status_bar_control: 7c84146799e6a076315cc1550f78ef53aae3e446
|
status_bar_control: 7c84146799e6a076315cc1550f78ef53aae3e446
|
||||||
system_proxy: bec1a5c5af67dd3e3ebf43979400a8756c04cc44
|
system_proxy: bec1a5c5af67dd3e3ebf43979400a8756c04cc44
|
||||||
Toast: ec33c32b8688982cecc6348adeae667c1b9938da
|
Toast: ec33c32b8688982cecc6348adeae667c1b9938da
|
||||||
url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b
|
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
||||||
volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9
|
volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9
|
||||||
wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47
|
wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1
|
||||||
webview_cookie_manager: eaf920722b493bd0f7611b5484771ca53fed03f7
|
webview_cookie_manager: eaf920722b493bd0f7611b5484771ca53fed03f7
|
||||||
webview_flutter_wkwebview: 4f3e50f7273d31e5500066ed267e3ae4309c5ae4
|
webview_flutter_wkwebview: be0f0d33777f1bfd0c9fdcb594786704dbf65f36
|
||||||
|
|
||||||
PODFILE CHECKSUM: 637cd290bed23275b5f5ffcc7eb1e73d0a5fb2be
|
PODFILE CHECKSUM: 637cd290bed23275b5f5ffcc7eb1e73d0a5fb2be
|
||||||
|
|
||||||
|
|||||||
@ -156,7 +156,7 @@
|
|||||||
97C146E61CF9000F007C117D /* Project object */ = {
|
97C146E61CF9000F007C117D /* Project object */ = {
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastUpgradeCheck = 1430;
|
LastUpgradeCheck = 1510;
|
||||||
ORGANIZATIONNAME = "";
|
ORGANIZATIONNAME = "";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
97C146ED1CF9000F007C117D = {
|
97C146ED1CF9000F007C117D = {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1430"
|
LastUpgradeVersion = "1510"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
|
|||||||
@ -124,7 +124,7 @@ class EpisodeBottomSheet {
|
|||||||
});
|
});
|
||||||
return Container(
|
return Container(
|
||||||
height: sheetHeight,
|
height: sheetHeight,
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
buildTitle(),
|
buildTitle(),
|
||||||
|
|||||||
@ -13,8 +13,8 @@ class Skeleton extends StatelessWidget {
|
|||||||
var shimmerGradient = LinearGradient(
|
var shimmerGradient = LinearGradient(
|
||||||
colors: [
|
colors: [
|
||||||
Colors.transparent,
|
Colors.transparent,
|
||||||
Theme.of(context).colorScheme.background.withAlpha(10),
|
Theme.of(context).colorScheme.surface.withAlpha(10),
|
||||||
Theme.of(context).colorScheme.background.withAlpha(10),
|
Theme.of(context).colorScheme.surface.withAlpha(10),
|
||||||
Colors.transparent,
|
Colors.transparent,
|
||||||
],
|
],
|
||||||
stops: const [
|
stops: const [
|
||||||
|
|||||||
@ -14,7 +14,7 @@ class StatDanMu extends StatelessWidget {
|
|||||||
Map<String, Color> colorObject = {
|
Map<String, Color> colorObject = {
|
||||||
'white': Colors.white,
|
'white': Colors.white,
|
||||||
'gray': Theme.of(context).colorScheme.outline,
|
'gray': Theme.of(context).colorScheme.outline,
|
||||||
'black': Theme.of(context).colorScheme.onBackground.withOpacity(0.8),
|
'black': Theme.of(context).colorScheme.onSurface.withOpacity(0.8),
|
||||||
};
|
};
|
||||||
Color color = colorObject[theme]!;
|
Color color = colorObject[theme]!;
|
||||||
return Row(
|
return Row(
|
||||||
|
|||||||
@ -14,7 +14,7 @@ class StatView extends StatelessWidget {
|
|||||||
Map<String, Color> colorObject = {
|
Map<String, Color> colorObject = {
|
||||||
'white': Colors.white,
|
'white': Colors.white,
|
||||||
'gray': Theme.of(context).colorScheme.outline,
|
'gray': Theme.of(context).colorScheme.outline,
|
||||||
'black': Theme.of(context).colorScheme.onBackground.withOpacity(0.8),
|
'black': Theme.of(context).colorScheme.onSurface.withOpacity(0.8),
|
||||||
};
|
};
|
||||||
Color color = colorObject[theme]!;
|
Color color = colorObject[theme]!;
|
||||||
return Row(
|
return Row(
|
||||||
|
|||||||
@ -20,11 +20,13 @@ import 'network_img_layer.dart';
|
|||||||
class VideoCardV extends StatelessWidget {
|
class VideoCardV extends StatelessWidget {
|
||||||
final dynamic videoItem;
|
final dynamic videoItem;
|
||||||
final int crossAxisCount;
|
final int crossAxisCount;
|
||||||
|
final Function? blockUserCb;
|
||||||
|
|
||||||
const VideoCardV({
|
const VideoCardV({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.videoItem,
|
required this.videoItem,
|
||||||
required this.crossAxisCount,
|
required this.crossAxisCount,
|
||||||
|
this.blockUserCb,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
bool isStringNumeric(String str) {
|
bool isStringNumeric(String str) {
|
||||||
@ -157,7 +159,11 @@ class VideoCardV extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
VideoContent(videoItem: videoItem, crossAxisCount: crossAxisCount)
|
VideoContent(
|
||||||
|
videoItem: videoItem,
|
||||||
|
crossAxisCount: crossAxisCount,
|
||||||
|
blockUserCb: blockUserCb,
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -167,9 +173,14 @@ class VideoCardV extends StatelessWidget {
|
|||||||
class VideoContent extends StatelessWidget {
|
class VideoContent extends StatelessWidget {
|
||||||
final dynamic videoItem;
|
final dynamic videoItem;
|
||||||
final int crossAxisCount;
|
final int crossAxisCount;
|
||||||
const VideoContent(
|
final Function? blockUserCb;
|
||||||
{Key? key, required this.videoItem, required this.crossAxisCount})
|
|
||||||
: super(key: key);
|
const VideoContent({
|
||||||
|
Key? key,
|
||||||
|
required this.videoItem,
|
||||||
|
required this.crossAxisCount,
|
||||||
|
this.blockUserCb,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
Widget _buildBadge(String text, String type, [double fs = 12]) {
|
Widget _buildBadge(String text, String type, [double fs = 12]) {
|
||||||
return PBadge(
|
return PBadge(
|
||||||
@ -241,7 +252,10 @@ class VideoContent extends StatelessWidget {
|
|||||||
useRootNavigator: true,
|
useRootNavigator: true,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return MorePanel(videoItem: videoItem);
|
return MorePanel(
|
||||||
|
videoItem: videoItem,
|
||||||
|
blockUserCb: blockUserCb,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -297,11 +311,17 @@ class VideoStat extends StatelessWidget {
|
|||||||
|
|
||||||
class MorePanel extends StatelessWidget {
|
class MorePanel extends StatelessWidget {
|
||||||
final dynamic videoItem;
|
final dynamic videoItem;
|
||||||
const MorePanel({super.key, required this.videoItem});
|
final Function? blockUserCb;
|
||||||
|
const MorePanel({
|
||||||
|
super.key,
|
||||||
|
required this.videoItem,
|
||||||
|
this.blockUserCb,
|
||||||
|
});
|
||||||
|
|
||||||
Future<dynamic> menuActionHandler(String type) async {
|
Future<dynamic> menuActionHandler(String type) async {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'block':
|
case 'block':
|
||||||
|
Get.back();
|
||||||
blockUser();
|
blockUser();
|
||||||
break;
|
break;
|
||||||
case 'watchLater':
|
case 'watchLater':
|
||||||
@ -338,7 +358,10 @@ class MorePanel extends StatelessWidget {
|
|||||||
reSrc: 11,
|
reSrc: 11,
|
||||||
);
|
);
|
||||||
SmartDialog.dismiss();
|
SmartDialog.dismiss();
|
||||||
SmartDialog.showToast(res['msg'] ?? '成功');
|
if (res['status']) {
|
||||||
|
blockUserCb?.call(videoItem.owner.mid);
|
||||||
|
}
|
||||||
|
SmartDialog.showToast(res['msg']);
|
||||||
},
|
},
|
||||||
child: const Text('确认'),
|
child: const Text('确认'),
|
||||||
)
|
)
|
||||||
|
|||||||
@ -400,12 +400,24 @@ class Api {
|
|||||||
'${HttpString.passBaseUrl}/x/passport-login/captcha?source=main_web';
|
'${HttpString.passBaseUrl}/x/passport-login/captcha?source=main_web';
|
||||||
|
|
||||||
// web端短信验证码
|
// web端短信验证码
|
||||||
static const String smsCode =
|
static const String webSmsCode =
|
||||||
'${HttpString.passBaseUrl}/x/passport-login/web/sms/send';
|
'${HttpString.passBaseUrl}/x/passport-login/web/sms/send';
|
||||||
|
|
||||||
// web端验证码登录
|
// web端验证码登录
|
||||||
|
static const String webSmsLogin =
|
||||||
|
'${HttpString.passBaseUrl}/x/passport-login/web/login/sms';
|
||||||
|
|
||||||
// web端密码登录
|
// web端密码登录
|
||||||
|
static const String loginInByWebPwd =
|
||||||
|
'${HttpString.passBaseUrl}/x/passport-login/web/login';
|
||||||
|
|
||||||
|
// web端二维码
|
||||||
|
static const String qrCodeApi =
|
||||||
|
'${HttpString.passBaseUrl}/x/passport-login/web/qrcode/generate';
|
||||||
|
|
||||||
|
// 扫码登录
|
||||||
|
static const String loginInByQrcode =
|
||||||
|
'${HttpString.passBaseUrl}/x/passport-login/web/qrcode/poll';
|
||||||
|
|
||||||
// app端短信验证码
|
// app端短信验证码
|
||||||
static const String appSmsCode =
|
static const String appSmsCode =
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import 'dart:math';
|
|||||||
import 'package:crypto/crypto.dart';
|
import 'package:crypto/crypto.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:encrypt/encrypt.dart';
|
import 'package:encrypt/encrypt.dart';
|
||||||
|
import 'package:pilipala/http/constants.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
import '../models/login/index.dart';
|
import '../models/login/index.dart';
|
||||||
import '../utils/login.dart';
|
import '../utils/login.dart';
|
||||||
@ -21,32 +22,32 @@ class LoginHttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future sendSmsCode({
|
// static Future sendSmsCode({
|
||||||
int? cid,
|
// int? cid,
|
||||||
required int tel,
|
// required int tel,
|
||||||
required String token,
|
// required String token,
|
||||||
required String challenge,
|
// required String challenge,
|
||||||
required String validate,
|
// required String validate,
|
||||||
required String seccode,
|
// required String seccode,
|
||||||
}) async {
|
// }) async {
|
||||||
var res = await Request().post(
|
// var res = await Request().post(
|
||||||
Api.appSmsCode,
|
// Api.appSmsCode,
|
||||||
data: {
|
// data: {
|
||||||
'cid': cid,
|
// 'cid': cid,
|
||||||
'tel': tel,
|
// 'tel': tel,
|
||||||
"source": "main_web",
|
// "source": "main_web",
|
||||||
'token': token,
|
// 'token': token,
|
||||||
'challenge': challenge,
|
// 'challenge': challenge,
|
||||||
'validate': validate,
|
// 'validate': validate,
|
||||||
'seccode': seccode,
|
// 'seccode': seccode,
|
||||||
},
|
// },
|
||||||
options: Options(
|
// options: Options(
|
||||||
contentType: Headers.formUrlEncodedContentType,
|
// contentType: Headers.formUrlEncodedContentType,
|
||||||
// headers: {'user-agent': ApiConstants.userAgent}
|
// // headers: {'user-agent': ApiConstants.userAgent}
|
||||||
),
|
// ),
|
||||||
);
|
// );
|
||||||
print(res);
|
// print(res);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// web端验证码
|
// web端验证码
|
||||||
static Future sendWebSmsCode({
|
static Future sendWebSmsCode({
|
||||||
@ -60,6 +61,7 @@ class LoginHttp {
|
|||||||
Map data = {
|
Map data = {
|
||||||
'cid': cid,
|
'cid': cid,
|
||||||
'tel': tel,
|
'tel': tel,
|
||||||
|
"source": "main_web",
|
||||||
'token': token,
|
'token': token,
|
||||||
'challenge': challenge,
|
'challenge': challenge,
|
||||||
'validate': validate,
|
'validate': validate,
|
||||||
@ -67,17 +69,56 @@ class LoginHttp {
|
|||||||
};
|
};
|
||||||
FormData formData = FormData.fromMap({...data});
|
FormData formData = FormData.fromMap({...data});
|
||||||
var res = await Request().post(
|
var res = await Request().post(
|
||||||
Api.smsCode,
|
Api.webSmsCode,
|
||||||
data: formData,
|
data: formData,
|
||||||
options: Options(
|
options: Options(
|
||||||
contentType: Headers.formUrlEncodedContentType,
|
contentType: Headers.formUrlEncodedContentType,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
print(res);
|
if (res.data['code'] == 0) {
|
||||||
|
return {
|
||||||
|
'status': true,
|
||||||
|
'data': res.data['data'],
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {'status': false, 'data': [], 'msg': res.data['message']};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// web端验证码登录
|
// web端验证码登录
|
||||||
static Future loginInByWebSmsCode() async {}
|
static Future loginInByWebSmsCode({
|
||||||
|
int? cid,
|
||||||
|
required int tel,
|
||||||
|
required int code,
|
||||||
|
required String captchaKey,
|
||||||
|
}) async {
|
||||||
|
// webSmsLogin
|
||||||
|
Map data = {
|
||||||
|
"cid": cid,
|
||||||
|
"tel": tel,
|
||||||
|
"code": code,
|
||||||
|
"source": "main_mini",
|
||||||
|
"keep": 0,
|
||||||
|
"captcha_key": captchaKey,
|
||||||
|
"go_url": HttpString.baseUrl
|
||||||
|
};
|
||||||
|
FormData formData = FormData.fromMap({...data});
|
||||||
|
var res = await Request().post(
|
||||||
|
Api.webSmsLogin,
|
||||||
|
data: formData,
|
||||||
|
options: Options(
|
||||||
|
contentType: Headers.formUrlEncodedContentType,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {
|
||||||
|
'status': true,
|
||||||
|
'data': res.data['data'],
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {'status': false, 'data': [], 'msg': res.data['message']};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// web端密码登录
|
// web端密码登录
|
||||||
static Future liginInByWebPwd() async {}
|
static Future liginInByWebPwd() async {}
|
||||||
@ -173,4 +214,69 @@ class LoginHttp {
|
|||||||
);
|
);
|
||||||
print(res);
|
print(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// web端密码登录
|
||||||
|
static Future loginInByWebPwd({
|
||||||
|
required int username,
|
||||||
|
required String password,
|
||||||
|
required String token,
|
||||||
|
required String challenge,
|
||||||
|
required String validate,
|
||||||
|
required String seccode,
|
||||||
|
}) async {
|
||||||
|
Map data = {
|
||||||
|
'username': username,
|
||||||
|
'password': password,
|
||||||
|
'keep': 0,
|
||||||
|
'token': token,
|
||||||
|
'challenge': challenge,
|
||||||
|
'validate': validate,
|
||||||
|
'seccode': seccode,
|
||||||
|
'source': 'main-fe-header',
|
||||||
|
"go_url": HttpString.baseUrl
|
||||||
|
};
|
||||||
|
FormData formData = FormData.fromMap({...data});
|
||||||
|
var res = await Request().post(
|
||||||
|
Api.loginInByWebPwd,
|
||||||
|
data: formData,
|
||||||
|
options: Options(
|
||||||
|
contentType: Headers.formUrlEncodedContentType,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {
|
||||||
|
'status': true,
|
||||||
|
'data': res.data['data'],
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {'status': false, 'data': [], 'msg': res.data['message']};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// web端登录二维码
|
||||||
|
static Future getWebQrcode() async {
|
||||||
|
var res = await Request().get(Api.qrCodeApi);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {
|
||||||
|
'status': true,
|
||||||
|
'data': res.data['data'],
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {'status': false, 'data': [], 'msg': res.data['message']};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// web端二维码轮询登录状态
|
||||||
|
static Future queryWebQrcodeStatus(String qrcodeKey) async {
|
||||||
|
var res = await Request()
|
||||||
|
.get(Api.loginInByQrcode, data: {'qrcode_key': qrcodeKey});
|
||||||
|
if (res.data['data']['code'] == 0) {
|
||||||
|
return {
|
||||||
|
'status': true,
|
||||||
|
'data': res.data['data'],
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {'status': false, 'data': [], 'msg': res.data['message']};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -387,9 +387,15 @@ class VideoHttp {
|
|||||||
'csrf': await Request.getCsrf(),
|
'csrf': await Request.getCsrf(),
|
||||||
});
|
});
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
return {'status': true, 'data': res.data['data']};
|
if (act == 5) {
|
||||||
|
List<int> blackMidsList =
|
||||||
|
setting.get(SettingBoxKey.blackMidsList, defaultValue: [-1]);
|
||||||
|
blackMidsList.add(mid);
|
||||||
|
setting.put(SettingBoxKey.blackMidsList, blackMidsList);
|
||||||
|
}
|
||||||
|
return {'status': true, 'data': res.data['data'], 'msg': '成功'};
|
||||||
} else {
|
} else {
|
||||||
return {'status': false, 'data': []};
|
return {'status': false, 'data': [], 'msg': res.data['message']};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
168
lib/main.dart
168
lib/main.dart
@ -23,7 +23,7 @@ import 'package:pilipala/utils/app_scheme.dart';
|
|||||||
import 'package:pilipala/utils/data.dart';
|
import 'package:pilipala/utils/data.dart';
|
||||||
import 'package:pilipala/utils/global_data.dart';
|
import 'package:pilipala/utils/global_data.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
import 'package:media_kit/media_kit.dart'; // Provides [Player], [Media], [Playlist] etc.
|
import 'package:media_kit/media_kit.dart';
|
||||||
import 'package:pilipala/utils/recommend_filter.dart';
|
import 'package:pilipala/utils/recommend_filter.dart';
|
||||||
import 'package:catcher_2/catcher_2.dart';
|
import 'package:catcher_2/catcher_2.dart';
|
||||||
import './services/loggeer.dart';
|
import './services/loggeer.dart';
|
||||||
@ -31,35 +31,21 @@ import './services/loggeer.dart';
|
|||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
MediaKit.ensureInitialized();
|
MediaKit.ensureInitialized();
|
||||||
SystemChrome.setPreferredOrientations(
|
await SystemChrome.setPreferredOrientations(
|
||||||
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown])
|
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
|
||||||
.then((_) async {
|
|
||||||
await GStrorage.init();
|
await GStrorage.init();
|
||||||
await setupServiceLocator();
|
await setupServiceLocator();
|
||||||
clearLogs();
|
clearLogs();
|
||||||
Request();
|
Request();
|
||||||
await Request.setCookie();
|
await Request.setCookie();
|
||||||
RecommendFilter();
|
|
||||||
|
|
||||||
// 异常捕获 logo记录
|
// 异常捕获 logo记录
|
||||||
final Catcher2Options debugConfig = Catcher2Options(
|
|
||||||
SilentReportMode(),
|
|
||||||
[
|
|
||||||
FileHandler(await getLogsPath()),
|
|
||||||
ConsoleHandler(
|
|
||||||
enableDeviceParameters: false,
|
|
||||||
enableApplicationParameters: false,
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
final Catcher2Options releaseConfig = Catcher2Options(
|
final Catcher2Options releaseConfig = Catcher2Options(
|
||||||
SilentReportMode(),
|
SilentReportMode(),
|
||||||
[FileHandler(await getLogsPath())],
|
[FileHandler(await getLogsPath())],
|
||||||
);
|
);
|
||||||
|
|
||||||
Catcher2(
|
Catcher2(
|
||||||
debugConfig: debugConfig,
|
|
||||||
releaseConfig: releaseConfig,
|
releaseConfig: releaseConfig,
|
||||||
runAppFunction: () {
|
runAppFunction: () {
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
@ -79,11 +65,8 @@ void main() async {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Data.init();
|
|
||||||
GlobalData();
|
|
||||||
PiliSchame.init();
|
PiliSchame.init();
|
||||||
DisableBatteryOpt();
|
DisableBatteryOpt();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
@ -124,6 +107,39 @@ class MyApp extends StatelessWidget {
|
|||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
return AndroidApp(
|
||||||
|
brandColor: brandColor,
|
||||||
|
isDynamicColor: isDynamicColor,
|
||||||
|
currentThemeValue: currentThemeValue,
|
||||||
|
textScale: textScale,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return OtherApp(
|
||||||
|
brandColor: brandColor,
|
||||||
|
currentThemeValue: currentThemeValue,
|
||||||
|
textScale: textScale,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AndroidApp extends StatelessWidget {
|
||||||
|
const AndroidApp({
|
||||||
|
super.key,
|
||||||
|
required this.brandColor,
|
||||||
|
required this.isDynamicColor,
|
||||||
|
required this.currentThemeValue,
|
||||||
|
required this.textScale,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Color brandColor;
|
||||||
|
final bool isDynamicColor;
|
||||||
|
final ThemeType currentThemeValue;
|
||||||
|
final double textScale;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
return DynamicColorBuilder(
|
return DynamicColorBuilder(
|
||||||
builder: ((ColorScheme? lightDynamic, ColorScheme? darkDynamic) {
|
builder: ((ColorScheme? lightDynamic, ColorScheme? darkDynamic) {
|
||||||
ColorScheme? lightColorScheme;
|
ColorScheme? lightColorScheme;
|
||||||
@ -143,50 +159,77 @@ class MyApp extends StatelessWidget {
|
|||||||
brightness: Brightness.dark,
|
brightness: Brightness.dark,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
return BuildMainApp(
|
||||||
|
lightColorScheme: lightColorScheme,
|
||||||
|
darkColorScheme: darkColorScheme,
|
||||||
|
currentThemeValue: currentThemeValue,
|
||||||
|
textScale: textScale,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ThemeData themeData = ThemeData(
|
class OtherApp extends StatelessWidget {
|
||||||
// colorScheme: currentThemeValue == ThemeType.dark
|
const OtherApp({
|
||||||
// ? darkColorScheme
|
super.key,
|
||||||
// : lightColorScheme,
|
required this.brandColor,
|
||||||
// );
|
required this.currentThemeValue,
|
||||||
|
required this.textScale,
|
||||||
|
});
|
||||||
|
|
||||||
// // 小白条、导航栏沉浸
|
final Color brandColor;
|
||||||
// if (Platform.isAndroid) {
|
final ThemeType currentThemeValue;
|
||||||
// List<String> versionParts = Platform.version.split('.');
|
final double textScale;
|
||||||
// int androidVersion = int.parse(versionParts[0]);
|
|
||||||
// if (androidVersion >= 29) {
|
@override
|
||||||
// SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
|
Widget build(BuildContext context) {
|
||||||
// }
|
return BuildMainApp(
|
||||||
// SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
|
lightColorScheme: ColorScheme.fromSeed(
|
||||||
// systemNavigationBarColor: GlobalData().enableMYBar
|
seedColor: brandColor,
|
||||||
// ? const Color(0x00010000)
|
brightness: Brightness.light,
|
||||||
// : themeData.canvasColor,
|
),
|
||||||
// systemNavigationBarDividerColor: GlobalData().enableMYBar
|
darkColorScheme: ColorScheme.fromSeed(
|
||||||
// ? const Color(0x00010000)
|
seedColor: brandColor,
|
||||||
// : themeData.canvasColor,
|
brightness: Brightness.dark,
|
||||||
// systemNavigationBarIconBrightness:
|
),
|
||||||
// currentThemeValue == ThemeType.dark
|
currentThemeValue: currentThemeValue,
|
||||||
// ? Brightness.light
|
textScale: textScale,
|
||||||
// : Brightness.dark,
|
);
|
||||||
// statusBarColor: Colors.transparent,
|
}
|
||||||
// ));
|
}
|
||||||
// }
|
|
||||||
|
class BuildMainApp extends StatelessWidget {
|
||||||
|
const BuildMainApp({
|
||||||
|
super.key,
|
||||||
|
required this.lightColorScheme,
|
||||||
|
required this.darkColorScheme,
|
||||||
|
required this.currentThemeValue,
|
||||||
|
required this.textScale,
|
||||||
|
});
|
||||||
|
|
||||||
|
final ColorScheme lightColorScheme;
|
||||||
|
final ColorScheme darkColorScheme;
|
||||||
|
final ThemeType currentThemeValue;
|
||||||
|
final double textScale;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final SnackBarThemeData snackBarTheme = SnackBarThemeData(
|
||||||
|
actionTextColor: lightColorScheme.primary,
|
||||||
|
backgroundColor: lightColorScheme.secondaryContainer,
|
||||||
|
closeIconColor: lightColorScheme.secondary,
|
||||||
|
contentTextStyle: TextStyle(color: lightColorScheme.secondary),
|
||||||
|
elevation: 20,
|
||||||
|
);
|
||||||
|
|
||||||
// 图片缓存
|
|
||||||
// PaintingBinding.instance.imageCache.maximumSizeBytes = 1000 << 20;
|
|
||||||
return GetMaterialApp(
|
return GetMaterialApp(
|
||||||
title: 'PiliPala',
|
title: 'PiliPala',
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
colorScheme: currentThemeValue == ThemeType.dark
|
colorScheme: currentThemeValue == ThemeType.dark
|
||||||
? darkColorScheme
|
? darkColorScheme
|
||||||
: lightColorScheme,
|
: lightColorScheme,
|
||||||
snackBarTheme: SnackBarThemeData(
|
snackBarTheme: snackBarTheme,
|
||||||
actionTextColor: lightColorScheme.primary,
|
|
||||||
backgroundColor: lightColorScheme.secondaryContainer,
|
|
||||||
closeIconColor: lightColorScheme.secondary,
|
|
||||||
contentTextStyle: TextStyle(color: lightColorScheme.secondary),
|
|
||||||
elevation: 20,
|
|
||||||
),
|
|
||||||
pageTransitionsTheme: const PageTransitionsTheme(
|
pageTransitionsTheme: const PageTransitionsTheme(
|
||||||
builders: <TargetPlatform, PageTransitionsBuilder>{
|
builders: <TargetPlatform, PageTransitionsBuilder>{
|
||||||
TargetPlatform.android: ZoomPageTransitionsBuilder(
|
TargetPlatform.android: ZoomPageTransitionsBuilder(
|
||||||
@ -199,13 +242,7 @@ class MyApp extends StatelessWidget {
|
|||||||
colorScheme: currentThemeValue == ThemeType.light
|
colorScheme: currentThemeValue == ThemeType.light
|
||||||
? lightColorScheme
|
? lightColorScheme
|
||||||
: darkColorScheme,
|
: darkColorScheme,
|
||||||
snackBarTheme: SnackBarThemeData(
|
snackBarTheme: snackBarTheme,
|
||||||
actionTextColor: darkColorScheme.primary,
|
|
||||||
backgroundColor: darkColorScheme.secondaryContainer,
|
|
||||||
closeIconColor: darkColorScheme.secondary,
|
|
||||||
contentTextStyle: TextStyle(color: darkColorScheme.secondary),
|
|
||||||
elevation: 20,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
localizationsDelegates: const [
|
localizationsDelegates: const [
|
||||||
GlobalCupertinoLocalizations.delegate,
|
GlobalCupertinoLocalizations.delegate,
|
||||||
@ -231,8 +268,11 @@ class MyApp extends StatelessWidget {
|
|||||||
VideoDetailPage.routeObserver,
|
VideoDetailPage.routeObserver,
|
||||||
SearchPage.routeObserver,
|
SearchPage.routeObserver,
|
||||||
],
|
],
|
||||||
);
|
onInit: () {
|
||||||
}),
|
RecommendFilter();
|
||||||
|
Data.init();
|
||||||
|
GlobalData();
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -415,6 +415,7 @@ class DynamicMajorModel {
|
|||||||
this.type,
|
this.type,
|
||||||
this.courses,
|
this.courses,
|
||||||
this.common,
|
this.common,
|
||||||
|
this.music,
|
||||||
});
|
});
|
||||||
|
|
||||||
DynamicArchiveModel? archive;
|
DynamicArchiveModel? archive;
|
||||||
@ -431,6 +432,7 @@ class DynamicMajorModel {
|
|||||||
String? type;
|
String? type;
|
||||||
Map? courses;
|
Map? courses;
|
||||||
Map? common;
|
Map? common;
|
||||||
|
Map? music;
|
||||||
|
|
||||||
DynamicMajorModel.fromJson(Map<String, dynamic> json) {
|
DynamicMajorModel.fromJson(Map<String, dynamic> json) {
|
||||||
archive = json['archive'] != null
|
archive = json['archive'] != null
|
||||||
@ -455,6 +457,7 @@ class DynamicMajorModel {
|
|||||||
type = json['type'];
|
type = json['type'];
|
||||||
courses = json['courses'] ?? {};
|
courses = json['courses'] ?? {};
|
||||||
common = json['common'] ?? {};
|
common = json['common'] ?? {};
|
||||||
|
music = json['music'] ?? {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -69,9 +69,10 @@ class RecVideoItemAppModel {
|
|||||||
: null;
|
: null;
|
||||||
// 由于app端api并不会直接返回与owner的关注状态
|
// 由于app端api并不会直接返回与owner的关注状态
|
||||||
// 所以借用推荐原因是否为“已关注”、“新关注”等判别关注状态,从而与web端接口等效
|
// 所以借用推荐原因是否为“已关注”、“新关注”等判别关注状态,从而与web端接口等效
|
||||||
|
RegExp regex = RegExp(r'已关注|新关注');
|
||||||
isFollowed = rcmdReason != null &&
|
isFollowed = rcmdReason != null &&
|
||||||
rcmdReason!.content != null &&
|
rcmdReason!.content != null &&
|
||||||
rcmdReason!.content!.contains('关注')
|
regex.hasMatch(rcmdReason!.content!)
|
||||||
? 1
|
? 1
|
||||||
: 0;
|
: 0;
|
||||||
// 如果是,就无需再显示推荐原因,交由view统一处理即可
|
// 如果是,就无需再显示推荐原因,交由view统一处理即可
|
||||||
|
|||||||
@ -194,7 +194,8 @@ class _BangumiInfoState extends State<BangumiInfo> {
|
|||||||
src: widget.bangumiDetail!.cover!,
|
src: widget.bangumiDetail!.cover!,
|
||||||
),
|
),
|
||||||
PBadge(
|
PBadge(
|
||||||
text: '评分 ${widget.bangumiDetail!.rating!['score']!}',
|
text:
|
||||||
|
'评分 ${widget.bangumiDetail?.rating?['score']! ?? '暂无'}',
|
||||||
top: null,
|
top: null,
|
||||||
right: 6,
|
right: 6,
|
||||||
bottom: 6,
|
bottom: 6,
|
||||||
|
|||||||
@ -20,10 +20,10 @@ class IntroDetail extends StatelessWidget {
|
|||||||
sheetHeight = localCache.get('sheetHeight');
|
sheetHeight = localCache.get('sheetHeight');
|
||||||
TextStyle smallTitle = TextStyle(
|
TextStyle smallTitle = TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: Theme.of(context).colorScheme.onBackground,
|
color: Theme.of(context).colorScheme.onSurface,
|
||||||
);
|
);
|
||||||
return Container(
|
return Container(
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
padding: const EdgeInsets.only(left: 14, right: 14),
|
padding: const EdgeInsets.only(left: 14, right: 14),
|
||||||
height: sheetHeight,
|
height: sheetHeight,
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|||||||
@ -3,7 +3,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:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:nil/nil.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/utils/main_stream.dart';
|
import 'package:pilipala/utils/main_stream.dart';
|
||||||
@ -142,10 +141,10 @@ class _BangumiPageState extends State<BangumiPage>
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return nil;
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil;
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -216,7 +215,7 @@ class _BangumiPageState extends State<BangumiPage>
|
|||||||
(BuildContext context, int index) {
|
(BuildContext context, int index) {
|
||||||
return bangumiList!.isNotEmpty
|
return bangumiList!.isNotEmpty
|
||||||
? BangumiCardV(bangumiItem: bangumiList[index])
|
? BangumiCardV(bangumiItem: bangumiList[index])
|
||||||
: nil;
|
: const SizedBox();
|
||||||
},
|
},
|
||||||
childCount: bangumiList!.isNotEmpty ? bangumiList!.length : 10,
|
childCount: bangumiList!.isNotEmpty ? bangumiList!.length : 10,
|
||||||
),
|
),
|
||||||
|
|||||||
@ -162,13 +162,12 @@ class _DynamicsPageState extends State<DynamicsPage>
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.surfaceVariant
|
.surfaceContainerHighest
|
||||||
.withOpacity(0.7),
|
.withOpacity(0.7),
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
),
|
),
|
||||||
thumbDecoration: BoxDecoration(
|
thumbDecoration: BoxDecoration(
|
||||||
color:
|
color: Theme.of(context).colorScheme.surface,
|
||||||
Theme.of(context).colorScheme.background,
|
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
),
|
),
|
||||||
duration: const Duration(milliseconds: 300),
|
duration: const Duration(milliseconds: 300),
|
||||||
|
|||||||
@ -19,7 +19,7 @@ Widget addWidget(item, context, type, {floor = 1}) {
|
|||||||
};
|
};
|
||||||
Color bgColor = floor == 1
|
Color bgColor = floor == 1
|
||||||
? Theme.of(context).dividerColor.withOpacity(0.08)
|
? Theme.of(context).dividerColor.withOpacity(0.08)
|
||||||
: Theme.of(context).colorScheme.background;
|
: Theme.of(context).colorScheme.surface;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'ADDITIONAL_TYPE_UGC':
|
case 'ADDITIONAL_TYPE_UGC':
|
||||||
// 转发的投稿
|
// 转发的投稿
|
||||||
|
|||||||
@ -52,7 +52,7 @@ class AuthorPanel extends StatelessWidget {
|
|||||||
color: item.modules.moduleAuthor!.vip != null &&
|
color: item.modules.moduleAuthor!.vip != null &&
|
||||||
item.modules.moduleAuthor!.vip['status'] > 0
|
item.modules.moduleAuthor!.vip['status'] > 0
|
||||||
? const Color.fromARGB(255, 251, 100, 163)
|
? const Color.fromARGB(255, 251, 100, 163)
|
||||||
: Theme.of(context).colorScheme.onBackground,
|
: Theme.of(context).colorScheme.onSurface,
|
||||||
fontSize: Theme.of(context).textTheme.titleSmall!.fontSize,
|
fontSize: Theme.of(context).textTheme.titleSmall!.fontSize,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -238,6 +238,61 @@ Widget forWard(item, context, ctr, source, {floor = 1}) {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
case 'DYNAMIC_TYPE_MUSIC':
|
||||||
|
final Map music = item.modules.moduleDynamic.major.music;
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 8),
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
Get.toNamed('/webview', parameters: {
|
||||||
|
'url': "https:${music['jump_url']}",
|
||||||
|
'type': 'url',
|
||||||
|
'pageTitle': music['title']
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.only(left: 12, top: 10, right: 12, bottom: 10),
|
||||||
|
color: Theme.of(context).dividerColor.withOpacity(0.08),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
NetworkImgLayer(
|
||||||
|
width: 45,
|
||||||
|
height: 45,
|
||||||
|
src: music['cover'],
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
music['title'],
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 2),
|
||||||
|
Text(
|
||||||
|
music['label'],
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).colorScheme.outline,
|
||||||
|
fontSize:
|
||||||
|
Theme.of(context).textTheme.labelMedium!.fontSize,
|
||||||
|
),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// TextButton(onPressed: () {}, child: Text('123'))
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return const SizedBox(
|
return const SizedBox(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
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:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
@ -30,6 +31,31 @@ class _UpPanelState extends State<UpPanel> {
|
|||||||
liveList = widget.upData.liveList!;
|
liveList = widget.upData.liveList!;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onClickUp(data, i) {
|
||||||
|
currentMid = data.mid;
|
||||||
|
Get.find<DynamicsController>().mid.value = data.mid;
|
||||||
|
Get.find<DynamicsController>().upInfo.value = data;
|
||||||
|
Get.find<DynamicsController>().onSelectUp(data.mid);
|
||||||
|
int liveLen = liveList.length;
|
||||||
|
int upLen = upList.length;
|
||||||
|
double itemWidth = contentWidth + itemPadding.horizontal;
|
||||||
|
double screenWidth = MediaQuery.sizeOf(context).width;
|
||||||
|
double moveDistance = 0.0;
|
||||||
|
if (itemWidth * (upList.length + liveList.length) <= screenWidth) {
|
||||||
|
} else if ((upLen - i - 0.5) * itemWidth > screenWidth / 2) {
|
||||||
|
moveDistance = (i + liveLen + 0.5) * itemWidth + 46 - screenWidth / 2;
|
||||||
|
} else {
|
||||||
|
moveDistance = (upLen + liveLen) * itemWidth + 46 - screenWidth;
|
||||||
|
}
|
||||||
|
data.hasUpdate = false;
|
||||||
|
scrollController.animateTo(
|
||||||
|
moveDistance,
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
curve: Curves.linear,
|
||||||
|
);
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
listFormat();
|
listFormat();
|
||||||
@ -43,7 +69,7 @@ class _UpPanelState extends State<UpPanel> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
padding: const EdgeInsets.only(left: 16, right: 16),
|
padding: const EdgeInsets.only(left: 16, right: 16),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
@ -69,7 +95,7 @@ class _UpPanelState extends State<UpPanel> {
|
|||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
height: 90,
|
height: 90,
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Flexible(
|
Flexible(
|
||||||
@ -120,30 +146,10 @@ class _UpPanelState extends State<UpPanel> {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
feedBack();
|
feedBack();
|
||||||
if (data.type == 'up') {
|
if (data.type == 'up') {
|
||||||
currentMid = data.mid;
|
EasyThrottle.throttle('follow', const Duration(milliseconds: 300),
|
||||||
Get.find<DynamicsController>().mid.value = data.mid;
|
() {
|
||||||
Get.find<DynamicsController>().upInfo.value = data;
|
onClickUp(data, i);
|
||||||
Get.find<DynamicsController>().onSelectUp(data.mid);
|
});
|
||||||
int liveLen = liveList.length;
|
|
||||||
int upLen = upList.length;
|
|
||||||
double itemWidth = contentWidth + itemPadding.horizontal;
|
|
||||||
double screenWidth = MediaQuery.sizeOf(context).width;
|
|
||||||
double moveDistance = 0.0;
|
|
||||||
if (itemWidth * (upList.length + liveList.length) <= screenWidth) {
|
|
||||||
} else if ((upLen - i - 0.5) * itemWidth > screenWidth / 2) {
|
|
||||||
moveDistance =
|
|
||||||
(i + liveLen + 0.5) * itemWidth + 46 - screenWidth / 2;
|
|
||||||
} else {
|
|
||||||
moveDistance = (upLen + liveLen) * itemWidth + 46 - screenWidth;
|
|
||||||
}
|
|
||||||
data.hasUpdate = false;
|
|
||||||
scrollController.animateTo(
|
|
||||||
moveDistance,
|
|
||||||
duration: const Duration(milliseconds: 500),
|
|
||||||
curve: Curves.easeInOut,
|
|
||||||
);
|
|
||||||
|
|
||||||
setState(() {});
|
|
||||||
} else if (data.type == 'live') {
|
} else if (data.type == 'live') {
|
||||||
LiveItemModel liveItem = LiveItemModel.fromJson({
|
LiveItemModel liveItem = LiveItemModel.fromJson({
|
||||||
'title': data.title,
|
'title': data.title,
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
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:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pilipala/common/skeleton/video_card_h.dart';
|
||||||
import 'package:pilipala/common/widgets/http_error.dart';
|
import 'package:pilipala/common/widgets/http_error.dart';
|
||||||
import 'package:pilipala/pages/fav/index.dart';
|
import 'package:pilipala/pages/fav/index.dart';
|
||||||
import 'package:pilipala/pages/fav/widgets/item.dart';
|
import 'package:pilipala/pages/fav/widgets/item.dart';
|
||||||
@ -93,7 +94,12 @@ class _FavPageState extends State<FavPage> {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 骨架屏
|
// 骨架屏
|
||||||
return const Text('请求中');
|
return ListView.builder(
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return const VideoCardHSkeleton();
|
||||||
|
},
|
||||||
|
itemCount: 10,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@ -198,7 +198,8 @@ class HistoryItem extends StatelessWidget {
|
|||||||
duration: const Duration(milliseconds: 200),
|
duration: const Duration(milliseconds: 200),
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(
|
||||||
|
StyleString.imgRadius.x),
|
||||||
color: Colors.black.withOpacity(
|
color: Colors.black.withOpacity(
|
||||||
ctr!.enableMultiple.value &&
|
ctr!.enableMultiple.value &&
|
||||||
videoItem.checked
|
videoItem.checked
|
||||||
@ -243,7 +244,7 @@ class HistoryItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
videoItem.progress != 0
|
videoItem.progress != 0 && videoItem.duration != 0
|
||||||
? Positioned(
|
? Positioned(
|
||||||
left: 3,
|
left: 3,
|
||||||
right: 3,
|
right: 3,
|
||||||
|
|||||||
@ -10,9 +10,8 @@ class HistorySearchController extends GetxController {
|
|||||||
final FocusNode searchFocusNode = FocusNode();
|
final FocusNode searchFocusNode = FocusNode();
|
||||||
RxString searchKeyWord = ''.obs;
|
RxString searchKeyWord = ''.obs;
|
||||||
String hintText = '搜索';
|
String hintText = '搜索';
|
||||||
RxString loadingStatus = 'init'.obs;
|
RxBool loadingStatus = false.obs;
|
||||||
RxString loadingText = '加载中...'.obs;
|
RxString loadingText = '加载中...'.obs;
|
||||||
bool hasRequest = false;
|
|
||||||
late int mid;
|
late int mid;
|
||||||
RxString uname = ''.obs;
|
RxString uname = ''.obs;
|
||||||
int pn = 1;
|
int pn = 1;
|
||||||
@ -36,8 +35,7 @@ class HistorySearchController extends GetxController {
|
|||||||
|
|
||||||
// 提交搜索内容
|
// 提交搜索内容
|
||||||
void submit() {
|
void submit() {
|
||||||
loadingStatus.value = 'loading';
|
if (!loadingStatus.value) {
|
||||||
if (hasRequest) {
|
|
||||||
pn = 1;
|
pn = 1;
|
||||||
searchHistories();
|
searchHistories();
|
||||||
}
|
}
|
||||||
@ -48,6 +46,7 @@ class HistorySearchController extends GetxController {
|
|||||||
if (type == 'onLoad' && loadingText.value == '没有更多了') {
|
if (type == 'onLoad' && loadingText.value == '没有更多了') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
loadingStatus.value = true;
|
||||||
var res = await UserHttp.searchHistory(
|
var res = await UserHttp.searchHistory(
|
||||||
pn: pn,
|
pn: pn,
|
||||||
keyword: controller.value.text,
|
keyword: controller.value.text,
|
||||||
@ -63,9 +62,8 @@ class HistorySearchController extends GetxController {
|
|||||||
loadingText.value = '没有更多了';
|
loadingText.value = '没有更多了';
|
||||||
}
|
}
|
||||||
pn += 1;
|
pn += 1;
|
||||||
hasRequest = true;
|
|
||||||
}
|
}
|
||||||
loadingStatus.value = 'finish';
|
loadingStatus.value = false;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,6 +84,6 @@ class HistorySearchController extends GetxController {
|
|||||||
historyList.removeWhere((e) => e.kid == kid);
|
historyList.removeWhere((e) => e.kid == kid);
|
||||||
SmartDialog.showToast(res['msg']);
|
SmartDialog.showToast(res['msg']);
|
||||||
}
|
}
|
||||||
loadingStatus.value = 'finish';
|
// loadingStatus.value = fasle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@ 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:pilipala/common/skeleton/video_card_h.dart';
|
import 'package:pilipala/common/skeleton/video_card_h.dart';
|
||||||
import 'package:pilipala/common/widgets/http_error.dart';
|
|
||||||
import 'package:pilipala/common/widgets/no_data.dart';
|
import 'package:pilipala/common/widgets/no_data.dart';
|
||||||
import 'package:pilipala/pages/history/widgets/item.dart';
|
import 'package:pilipala/pages/history/widgets/item.dart';
|
||||||
|
|
||||||
@ -16,20 +15,19 @@ class HistorySearchPage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _HistorySearchPageState extends State<HistorySearchPage> {
|
class _HistorySearchPageState extends State<HistorySearchPage> {
|
||||||
final HistorySearchController _historySearchCtr =
|
final HistorySearchController _hisCtr = Get.put(HistorySearchController());
|
||||||
Get.put(HistorySearchController());
|
|
||||||
late ScrollController scrollController;
|
late ScrollController scrollController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
scrollController = _historySearchCtr.scrollController;
|
scrollController = _hisCtr.scrollController;
|
||||||
scrollController.addListener(
|
scrollController.addListener(
|
||||||
() {
|
() {
|
||||||
if (scrollController.position.pixels >=
|
if (scrollController.position.pixels >=
|
||||||
scrollController.position.maxScrollExtent - 300) {
|
scrollController.position.maxScrollExtent - 300) {
|
||||||
EasyThrottle.throttle('history', const Duration(seconds: 1), () {
|
EasyThrottle.throttle('history', const Duration(seconds: 1), () {
|
||||||
_historySearchCtr.onLoad();
|
_hisCtr.onLoad();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -50,19 +48,19 @@ class _HistorySearchPageState extends State<HistorySearchPage> {
|
|||||||
titleSpacing: 0,
|
titleSpacing: 0,
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () => _historySearchCtr.submit(),
|
onPressed: () => _hisCtr.submit(),
|
||||||
icon: const Icon(Icons.search_outlined, size: 22)),
|
icon: const Icon(Icons.search_outlined, size: 22)),
|
||||||
const SizedBox(width: 10)
|
const SizedBox(width: 10)
|
||||||
],
|
],
|
||||||
title: Obx(
|
title: Obx(
|
||||||
() => TextField(
|
() => TextField(
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
focusNode: _historySearchCtr.searchFocusNode,
|
focusNode: _hisCtr.searchFocusNode,
|
||||||
controller: _historySearchCtr.controller.value,
|
controller: _hisCtr.controller.value,
|
||||||
textInputAction: TextInputAction.search,
|
textInputAction: TextInputAction.search,
|
||||||
onChanged: (value) => _historySearchCtr.onChange(value),
|
onChanged: (value) => _hisCtr.onChange(value),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: _historySearchCtr.hintText,
|
hintText: _hisCtr.hintText,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
@ -70,104 +68,62 @@ class _HistorySearchPageState extends State<HistorySearchPage> {
|
|||||||
size: 22,
|
size: 22,
|
||||||
color: Theme.of(context).colorScheme.outline,
|
color: Theme.of(context).colorScheme.outline,
|
||||||
),
|
),
|
||||||
onPressed: () => _historySearchCtr.onClear(),
|
onPressed: () => _hisCtr.onClear(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onSubmitted: (String value) => _historySearchCtr.submit(),
|
onSubmitted: (String value) => _hisCtr.submit(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: Obx(
|
body: Obx(
|
||||||
() => Column(
|
() {
|
||||||
children: _historySearchCtr.loadingStatus.value == 'init'
|
return _hisCtr.loadingStatus.value && _hisCtr.historyList.isEmpty
|
||||||
? [const SizedBox()]
|
? ListView.builder(
|
||||||
: [
|
itemCount: 10,
|
||||||
Expanded(
|
itemBuilder: (context, index) {
|
||||||
child: FutureBuilder(
|
return const VideoCardHSkeleton();
|
||||||
future: _historySearchCtr.searchHistories(),
|
},
|
||||||
builder: (context, snapshot) {
|
)
|
||||||
if (snapshot.connectionState == ConnectionState.done) {
|
: _hisCtr.historyList.isNotEmpty
|
||||||
Map data = snapshot.data as Map;
|
|
||||||
if (data['status']) {
|
|
||||||
return Obx(
|
|
||||||
() => _historySearchCtr.historyList.isNotEmpty
|
|
||||||
? ListView.builder(
|
? ListView.builder(
|
||||||
controller: scrollController,
|
controller: scrollController,
|
||||||
itemCount:
|
itemCount: _hisCtr.historyList.length + 1,
|
||||||
_historySearchCtr.historyList.length +
|
|
||||||
1,
|
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
if (index ==
|
if (index == _hisCtr.historyList.length) {
|
||||||
_historySearchCtr
|
|
||||||
.historyList.length) {
|
|
||||||
return Container(
|
return Container(
|
||||||
height: MediaQuery.of(context)
|
height: MediaQuery.of(context).padding.bottom + 60,
|
||||||
.padding
|
|
||||||
.bottom +
|
|
||||||
60,
|
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
bottom: MediaQuery.of(context)
|
bottom: MediaQuery.of(context).padding.bottom),
|
||||||
.padding
|
|
||||||
.bottom),
|
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Obx(
|
child: Obx(
|
||||||
() => Text(
|
() => Text(
|
||||||
_historySearchCtr
|
_hisCtr.loadingText.value,
|
||||||
.loadingText.value,
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context)
|
color:
|
||||||
.colorScheme
|
Theme.of(context).colorScheme.outline,
|
||||||
.outline,
|
fontSize: 13,
|
||||||
fontSize: 13),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return HistoryItem(
|
return HistoryItem(
|
||||||
videoItem: _historySearchCtr
|
videoItem: _hisCtr.historyList[index],
|
||||||
.historyList[index],
|
ctr: _hisCtr,
|
||||||
ctr: _historySearchCtr,
|
|
||||||
onChoose: null,
|
onChoose: null,
|
||||||
onUpdateMultiple: () => null,
|
onUpdateMultiple: () => null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
: _historySearchCtr.loadingStatus.value ==
|
|
||||||
'loading'
|
|
||||||
? const SizedBox(child: Text('加载中...'))
|
|
||||||
: const CustomScrollView(
|
: const CustomScrollView(
|
||||||
slivers: <Widget>[
|
slivers: <Widget>[
|
||||||
NoData(),
|
NoData(),
|
||||||
],
|
],
|
||||||
),
|
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
return CustomScrollView(
|
|
||||||
slivers: <Widget>[
|
|
||||||
HttpError(
|
|
||||||
errMsg: data['msg'],
|
|
||||||
fn: () => setState(() {}),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 骨架屏
|
|
||||||
return ListView.builder(
|
|
||||||
itemCount: 10,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
return const VideoCardHSkeleton();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,8 +17,7 @@ class LiveRoomController extends GetxController {
|
|||||||
double volume = 0.0;
|
double volume = 0.0;
|
||||||
// 静音状态
|
// 静音状态
|
||||||
RxBool volumeOff = false.obs;
|
RxBool volumeOff = false.obs;
|
||||||
PlPlayerController plPlayerController =
|
PlPlayerController plPlayerController = PlPlayerController(videoType: 'live');
|
||||||
PlPlayerController.getInstance(videoType: 'live');
|
|
||||||
Rx<RoomInfoH5Model> roomInfoH5 = RoomInfoH5Model().obs;
|
Rx<RoomInfoH5Model> roomInfoH5 = RoomInfoH5Model().obs;
|
||||||
late bool enableCDN;
|
late bool enableCDN;
|
||||||
late int currentQn;
|
late int currentQn;
|
||||||
|
|||||||
@ -153,7 +153,8 @@ class _BottomControlState extends State<BottomControl> {
|
|||||||
size: 20,
|
size: 20,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
fuc: () => widget.controller!.triggerFullScreen(),
|
fuc: () => widget.controller!.triggerFullScreen(
|
||||||
|
status: !(widget.controller!.isFullScreen.value)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,11 +1,14 @@
|
|||||||
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:encrypt/encrypt.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/http/login.dart';
|
import 'package:pilipala/http/login.dart';
|
||||||
import 'package:gt3_flutter_plugin/gt3_flutter_plugin.dart';
|
import 'package:gt3_flutter_plugin/gt3_flutter_plugin.dart';
|
||||||
import 'package:pilipala/models/login/index.dart';
|
import 'package:pilipala/models/login/index.dart';
|
||||||
|
import 'package:pilipala/utils/login.dart';
|
||||||
|
|
||||||
class LoginPageController extends GetxController {
|
class LoginPageController extends GetxController {
|
||||||
final GlobalKey mobFormKey = GlobalKey<FormState>();
|
final GlobalKey mobFormKey = GlobalKey<FormState>();
|
||||||
@ -26,9 +29,23 @@ class LoginPageController extends GetxController {
|
|||||||
|
|
||||||
final Gt3FlutterPlugin captcha = Gt3FlutterPlugin();
|
final Gt3FlutterPlugin captcha = Gt3FlutterPlugin();
|
||||||
|
|
||||||
|
// 倒计时60s
|
||||||
|
RxInt seconds = 60.obs;
|
||||||
|
late Timer timer;
|
||||||
|
RxBool smsCodeSendStatus = false.obs;
|
||||||
|
|
||||||
// 默认密码登录
|
// 默认密码登录
|
||||||
RxInt loginType = 0.obs;
|
RxInt loginType = 0.obs;
|
||||||
|
|
||||||
|
late String captchaKey;
|
||||||
|
|
||||||
|
late int tel;
|
||||||
|
late int webSmsCode;
|
||||||
|
|
||||||
|
RxInt validSeconds = 180.obs;
|
||||||
|
late Timer validTimer;
|
||||||
|
late String qrcodeKey;
|
||||||
|
|
||||||
// 监听pageView切换
|
// 监听pageView切换
|
||||||
void onPageChange(int index) {
|
void onPageChange(int index) {
|
||||||
currentIndex.value = index;
|
currentIndex.value = index;
|
||||||
@ -43,6 +60,7 @@ class LoginPageController extends GetxController {
|
|||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
);
|
);
|
||||||
passwordTextFieldNode.requestFocus();
|
passwordTextFieldNode.requestFocus();
|
||||||
|
(mobFormKey.currentState as FormState).save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,18 +104,64 @@ class LoginPageController extends GetxController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证码登录
|
// web端密码登录
|
||||||
void loginInByCode() {
|
void loginInByWebPassword() async {
|
||||||
if ((msgCodeFormKey.currentState as FormState).validate()) {}
|
if ((passwordFormKey.currentState as FormState).validate()) {
|
||||||
|
getCaptcha((data) async {
|
||||||
|
CaptchaDataModel captchaData = data;
|
||||||
|
var webKeyRes = await LoginHttp.getWebKey();
|
||||||
|
if (webKeyRes['status']) {
|
||||||
|
String rhash = webKeyRes['data']['hash'];
|
||||||
|
String key = webKeyRes['data']['key'];
|
||||||
|
dynamic publicKey = RSAKeyParser().parse(key);
|
||||||
|
String passwordEncryptyed = Encrypter(RSA(publicKey: publicKey))
|
||||||
|
.encrypt(rhash + passwordTextController.text)
|
||||||
|
.base64;
|
||||||
|
var res = await LoginHttp.loginInByWebPwd(
|
||||||
|
username: tel,
|
||||||
|
password: passwordEncryptyed,
|
||||||
|
token: captchaData.token!,
|
||||||
|
challenge: captchaData.geetest!.challenge!,
|
||||||
|
validate: captchaData.validate!,
|
||||||
|
seccode: captchaData.seccode!,
|
||||||
|
);
|
||||||
|
if (res['status']) {
|
||||||
|
await LoginUtils.confirmLogin('', null);
|
||||||
|
} else {
|
||||||
|
SmartDialog.showToast(res['msg']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SmartDialog.showToast(webKeyRes['msg']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// app端验证码
|
// web端验证码登录
|
||||||
void getMsgCode() async {
|
void loginInByCode() async {
|
||||||
|
if ((msgCodeFormKey.currentState as FormState).validate()) {
|
||||||
|
(msgCodeFormKey.currentState as FormState).save();
|
||||||
|
var res = await LoginHttp.loginInByWebSmsCode(
|
||||||
|
cid: 86,
|
||||||
|
tel: tel,
|
||||||
|
code: webSmsCode,
|
||||||
|
captchaKey: captchaKey,
|
||||||
|
);
|
||||||
|
if (res['status']) {
|
||||||
|
await LoginUtils.confirmLogin('', null);
|
||||||
|
} else {
|
||||||
|
SmartDialog.showToast(res['msg']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取app端验证码
|
||||||
|
void getAppMsgCode() async {
|
||||||
getCaptcha((data) async {
|
getCaptcha((data) async {
|
||||||
CaptchaDataModel captchaData = data;
|
CaptchaDataModel captchaData = data;
|
||||||
var res = await LoginHttp.sendAppSmsCode(
|
var res = await LoginHttp.sendAppSmsCode(
|
||||||
cid: 86,
|
cid: 86,
|
||||||
tel: 13734077064,
|
tel: tel,
|
||||||
token: captchaData.token!,
|
token: captchaData.token!,
|
||||||
challenge: captchaData.geetest!.challenge!,
|
challenge: captchaData.geetest!.challenge!,
|
||||||
validate: captchaData.validate!,
|
validate: captchaData.validate!,
|
||||||
@ -121,7 +185,7 @@ class LoginPageController extends GetxController {
|
|||||||
captcha.addEventHandler(onShow: (Map<String, dynamic> message) async {
|
captcha.addEventHandler(onShow: (Map<String, dynamic> message) async {
|
||||||
SmartDialog.dismiss();
|
SmartDialog.dismiss();
|
||||||
}, onClose: (Map<String, dynamic> message) async {
|
}, onClose: (Map<String, dynamic> message) async {
|
||||||
SmartDialog.showToast('关闭验证');
|
SmartDialog.showToast('取消验证');
|
||||||
}, onResult: (Map<String, dynamic> message) async {
|
}, onResult: (Map<String, dynamic> message) async {
|
||||||
debugPrint("Captcha result: $message");
|
debugPrint("Captcha result: $message");
|
||||||
String code = message["code"];
|
String code = message["code"];
|
||||||
@ -201,4 +265,72 @@ class LoginPageController extends GetxController {
|
|||||||
captcha.startCaptcha(registerData);
|
captcha.startCaptcha(registerData);
|
||||||
} else {}
|
} else {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取web端验证码
|
||||||
|
void getWebMsgCode() async {
|
||||||
|
getCaptcha((data) async {
|
||||||
|
CaptchaDataModel captchaData = data;
|
||||||
|
var res = await LoginHttp.sendWebSmsCode(
|
||||||
|
cid: 86,
|
||||||
|
tel: tel,
|
||||||
|
token: captchaData.token!,
|
||||||
|
challenge: captchaData.geetest!.challenge!,
|
||||||
|
validate: captchaData.validate!,
|
||||||
|
seccode: captchaData.seccode!,
|
||||||
|
);
|
||||||
|
if (res['status']) {
|
||||||
|
captchaKey = res['data']['captcha_key'];
|
||||||
|
SmartDialog.showToast('验证码已发送');
|
||||||
|
// 倒计时60s
|
||||||
|
smsCodeSendStatus.value = true;
|
||||||
|
startTimer();
|
||||||
|
} else {
|
||||||
|
SmartDialog.showToast(res['msg']);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证码倒计时
|
||||||
|
void startTimer() {
|
||||||
|
timer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||||
|
if (seconds.value > 0) {
|
||||||
|
seconds.value--;
|
||||||
|
} else {
|
||||||
|
seconds.value = 60;
|
||||||
|
smsCodeSendStatus.value = false;
|
||||||
|
timer.cancel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取登录二维码
|
||||||
|
Future getWebQrcode() async {
|
||||||
|
var res = await LoginHttp.getWebQrcode();
|
||||||
|
validSeconds.value = 180;
|
||||||
|
if (res['status']) {
|
||||||
|
qrcodeKey = res['data']['qrcode_key'];
|
||||||
|
validTimer = Timer.periodic(const Duration(seconds: 1), (validTimer) {
|
||||||
|
if (validSeconds.value > 0) {
|
||||||
|
validSeconds.value--;
|
||||||
|
queryWebQrcodeStatus();
|
||||||
|
} else {
|
||||||
|
getWebQrcode();
|
||||||
|
validTimer.cancel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
} else {
|
||||||
|
SmartDialog.showToast(res['msg']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 轮询二维码登录状态
|
||||||
|
Future queryWebQrcodeStatus() async {
|
||||||
|
var res = await LoginHttp.queryWebQrcodeStatus(qrcodeKey);
|
||||||
|
if (res['status']) {
|
||||||
|
await LoginUtils.confirmLogin('', null);
|
||||||
|
validTimer.cancel();
|
||||||
|
Get.back();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
|
|
||||||
import 'controller.dart';
|
import 'controller.dart';
|
||||||
|
|
||||||
@ -37,6 +38,105 @@ class _LoginPageState extends State<LoginPage> {
|
|||||||
icon: const Icon(Icons.arrow_back),
|
icon: const Icon(Icons.arrow_back),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
tooltip: '浏览器打开',
|
||||||
|
onPressed: () {
|
||||||
|
Get.offNamed(
|
||||||
|
'/webview',
|
||||||
|
parameters: {
|
||||||
|
'url': 'https://passport.bilibili.com/h5-app/passport/login',
|
||||||
|
'type': 'login',
|
||||||
|
'pageTitle': '登录bilibili',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.language),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
tooltip: '二维码登录',
|
||||||
|
onPressed: () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) {
|
||||||
|
return StatefulBuilder(
|
||||||
|
builder: (context, StateSetter setState) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Row(
|
||||||
|
children: [
|
||||||
|
const Text('扫码登录'),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.refresh),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
contentPadding: const EdgeInsets.fromLTRB(0, 0, 0, 4),
|
||||||
|
content: AspectRatio(
|
||||||
|
aspectRatio: 1,
|
||||||
|
child: Container(
|
||||||
|
width: 200,
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
child: FutureBuilder(
|
||||||
|
future: _loginPageCtr.getWebQrcode(),
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState ==
|
||||||
|
ConnectionState.done) {
|
||||||
|
if (snapshot.data == null) {
|
||||||
|
return const SizedBox();
|
||||||
|
}
|
||||||
|
Map data = snapshot.data as Map;
|
||||||
|
return QrImageView(
|
||||||
|
data: data['data']['url'],
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return const Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {},
|
||||||
|
child: Obx(() {
|
||||||
|
return Text(
|
||||||
|
'有效期: ${_loginPageCtr.validSeconds.value}s',
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {},
|
||||||
|
child: Text(
|
||||||
|
'检查登录状态',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.titleMedium!
|
||||||
|
.fontSize,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.qr_code),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 22),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
body: PageView(
|
body: PageView(
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
@ -93,35 +193,12 @@ class _LoginPageState extends State<LoginPage> {
|
|||||||
validator: (v) {
|
validator: (v) {
|
||||||
return v!.trim().isNotEmpty ? null : "手机号码不能为空";
|
return v!.trim().isNotEmpty ? null : "手机号码不能为空";
|
||||||
},
|
},
|
||||||
onSaved: (val) {
|
onSaved: (val) => _loginPageCtr.tel = int.parse(val!),
|
||||||
print(val);
|
|
||||||
},
|
|
||||||
onEditingComplete: () {
|
onEditingComplete: () {
|
||||||
_loginPageCtr.nextStep();
|
_loginPageCtr.nextStep();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
Get.offNamed(
|
|
||||||
'/webview',
|
|
||||||
parameters: {
|
|
||||||
'url':
|
|
||||||
'https://passport.bilibili.com/h5-app/passport/login',
|
|
||||||
'type': 'login',
|
|
||||||
'pageTitle': '登录bilibili',
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 2),
|
|
||||||
child: Text(
|
|
||||||
'使用网页端登录',
|
|
||||||
style: TextStyle(
|
|
||||||
color: Theme.of(context).colorScheme.primary),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
@ -236,7 +313,7 @@ class _LoginPageState extends State<LoginPage> {
|
|||||||
.primary, // 设置按钮背景色
|
.primary, // 设置按钮背景色
|
||||||
),
|
),
|
||||||
onPressed: () =>
|
onPressed: () =>
|
||||||
_loginPageCtr.loginInByAppPassword(),
|
_loginPageCtr.loginInByWebPassword(),
|
||||||
child: const Text('确认登录'),
|
child: const Text('确认登录'),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
@ -308,21 +385,28 @@ class _LoginPageState extends State<LoginPage> {
|
|||||||
? null
|
? null
|
||||||
: "验证码不能为空";
|
: "验证码不能为空";
|
||||||
},
|
},
|
||||||
onSaved: (val) {
|
onSaved: (val) => _loginPageCtr.webSmsCode =
|
||||||
print(val);
|
int.parse(val!),
|
||||||
},
|
|
||||||
),
|
),
|
||||||
Positioned(
|
Obx(() {
|
||||||
|
return Positioned(
|
||||||
right: 8,
|
right: 8,
|
||||||
top: 4,
|
top: 0,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
onPressed: () =>
|
onPressed: _loginPageCtr
|
||||||
_loginPageCtr.getMsgCode(),
|
.smsCodeSendStatus.value
|
||||||
child: const Text('获取验证码'),
|
? null
|
||||||
),
|
: () =>
|
||||||
),
|
_loginPageCtr.getWebMsgCode(),
|
||||||
|
child: _loginPageCtr
|
||||||
|
.smsCodeSendStatus.value
|
||||||
|
? Text(
|
||||||
|
'重新获取(${_loginPageCtr.seconds.value}s)')
|
||||||
|
: const Text('获取验证码')),
|
||||||
),
|
),
|
||||||
|
);
|
||||||
|
})
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -105,7 +105,7 @@ class _MediaPageState extends State<MediaPage>
|
|||||||
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
onTap: () {},
|
onTap: () => Get.toNamed('/fav'),
|
||||||
leading: null,
|
leading: null,
|
||||||
dense: true,
|
dense: true,
|
||||||
title: Padding(
|
title: Padding(
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import 'package:pilipala/http/user.dart';
|
|||||||
import 'package:pilipala/models/common/theme_type.dart';
|
import 'package:pilipala/models/common/theme_type.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/route_push.dart';
|
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
|
|
||||||
class MineController extends GetxController {
|
class MineController extends GetxController {
|
||||||
@ -34,8 +33,8 @@ class MineController extends GetxController {
|
|||||||
|
|
||||||
onLogin() async {
|
onLogin() async {
|
||||||
if (!userLogin.value) {
|
if (!userLogin.value) {
|
||||||
RoutePush.loginPush();
|
// RoutePush.loginPush();
|
||||||
// Get.toNamed('/loginPage');
|
Get.toNamed('/loginPage');
|
||||||
} else {
|
} else {
|
||||||
int mid = userInfo.value.mid!;
|
int mid = userInfo.value.mid!;
|
||||||
String face = userInfo.value.face!;
|
String face = userInfo.value.face!;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.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/video.dart';
|
import 'package:pilipala/http/video.dart';
|
||||||
@ -106,4 +107,10 @@ class RcmdController extends GetxController {
|
|||||||
duration: const Duration(milliseconds: 500), curve: Curves.easeInOut);
|
duration: const Duration(milliseconds: 500), curve: Curves.easeInOut);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void blockUserCb(mid) {
|
||||||
|
videoList.removeWhere((e) => e.owner.mid == mid);
|
||||||
|
videoList.refresh();
|
||||||
|
SmartDialog.showToast('已移除相关视频');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -146,6 +146,7 @@ class _RcmdPageState extends State<RcmdPage>
|
|||||||
? VideoCardV(
|
? VideoCardV(
|
||||||
videoItem: videoList[index],
|
videoItem: videoList[index],
|
||||||
crossAxisCount: crossAxisCount,
|
crossAxisCount: crossAxisCount,
|
||||||
|
blockUserCb: (mid) => ctr.blockUserCb(mid),
|
||||||
)
|
)
|
||||||
: const VideoCardVSkeleton();
|
: const VideoCardVSkeleton();
|
||||||
},
|
},
|
||||||
|
|||||||
@ -18,7 +18,10 @@ class SearchText extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Material(
|
return Material(
|
||||||
color: Theme.of(context).colorScheme.surfaceVariant.withOpacity(0.5),
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.surfaceContainerHighest
|
||||||
|
.withOpacity(0.5),
|
||||||
borderRadius: BorderRadius.circular(6),
|
borderRadius: BorderRadius.circular(6),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
|
|||||||
@ -66,7 +66,7 @@ class _FontSizeSelectPageState extends State<FontSizeSelectPage> {
|
|||||||
.colorScheme
|
.colorScheme
|
||||||
.primary
|
.primary
|
||||||
.withOpacity(0.3))),
|
.withOpacity(0.3))),
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@ -41,7 +41,8 @@ class _LogsPageState extends State<LogsPage> {
|
|||||||
.replaceAll('DEVICE INFO', '设备信息')
|
.replaceAll('DEVICE INFO', '设备信息')
|
||||||
.replaceAll('APP INFO', '应用信息')
|
.replaceAll('APP INFO', '应用信息')
|
||||||
.replaceAll('ERROR', '错误信息')
|
.replaceAll('ERROR', '错误信息')
|
||||||
.replaceAll('STACK TRACE', '错误堆栈');
|
.replaceAll('STACK TRACE', '错误堆栈')
|
||||||
|
.replaceAll('#', 'Line');
|
||||||
}).toList();
|
}).toList();
|
||||||
List<Map<String, dynamic>> result = [];
|
List<Map<String, dynamic>> result = [];
|
||||||
for (String i in contentList) {
|
for (String i in contentList) {
|
||||||
@ -50,7 +51,7 @@ class _LogsPageState extends State<LogsPage> {
|
|||||||
.split("\n")
|
.split("\n")
|
||||||
.map((l) {
|
.map((l) {
|
||||||
if (l.startsWith("Crash occurred on")) {
|
if (l.startsWith("Crash occurred on")) {
|
||||||
date = DateTime.parse(
|
date = DateTime.tryParse(
|
||||||
l.split("Crash occurred on")[1].trim().split('.')[0],
|
l.split("Crash occurred on")[1].trim().split('.')[0],
|
||||||
);
|
);
|
||||||
return "";
|
return "";
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
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:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pilipala/common/skeleton/video_card_h.dart';
|
||||||
import 'package:pilipala/common/widgets/http_error.dart';
|
import 'package:pilipala/common/widgets/http_error.dart';
|
||||||
import 'package:pilipala/utils/route_push.dart';
|
import 'package:pilipala/utils/route_push.dart';
|
||||||
import 'controller.dart';
|
import 'controller.dart';
|
||||||
@ -87,7 +88,12 @@ class _SubPageState extends State<SubPage> {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 骨架屏
|
// 骨架屏
|
||||||
return const Text('请求中');
|
return ListView.builder(
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return const VideoCardHSkeleton();
|
||||||
|
},
|
||||||
|
itemCount: 10,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@ -74,7 +74,7 @@ class VideoDetailController extends GetxController
|
|||||||
final scaffoldKey = GlobalKey<ScaffoldState>();
|
final scaffoldKey = GlobalKey<ScaffoldState>();
|
||||||
RxString bgCover = ''.obs;
|
RxString bgCover = ''.obs;
|
||||||
RxString cover = ''.obs;
|
RxString cover = ''.obs;
|
||||||
PlPlayerController plPlayerController = PlPlayerController.getInstance();
|
PlPlayerController plPlayerController = PlPlayerController();
|
||||||
|
|
||||||
late VideoItem firstVideo;
|
late VideoItem firstVideo;
|
||||||
late AudioItem firstAudio;
|
late AudioItem firstAudio;
|
||||||
@ -233,7 +233,7 @@ class VideoDetailController extends GetxController
|
|||||||
audio,
|
audio,
|
||||||
seekToTime,
|
seekToTime,
|
||||||
duration,
|
duration,
|
||||||
bool autoplay = true,
|
bool? autoplay,
|
||||||
}) async {
|
}) async {
|
||||||
/// 设置/恢复 屏幕亮度
|
/// 设置/恢复 屏幕亮度
|
||||||
if (brightness != null) {
|
if (brightness != null) {
|
||||||
@ -266,7 +266,7 @@ class VideoDetailController extends GetxController
|
|||||||
cid: cid.value,
|
cid: cid.value,
|
||||||
enableHeart: enableHeart,
|
enableHeart: enableHeart,
|
||||||
isFirstTime: isFirstTime,
|
isFirstTime: isFirstTime,
|
||||||
autoplay: autoplay,
|
autoplay: autoplay ?? autoPlay.value,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// 开启自动全屏时,在player初始化完成后立即传入headerControl
|
/// 开启自动全屏时,在player初始化完成后立即传入headerControl
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:lottie/lottie.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/video/detail/index.dart';
|
import 'package:pilipala/pages/video/detail/index.dart';
|
||||||
@ -97,11 +98,14 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return const SliverToBoxAdapter(
|
return SliverToBoxAdapter(
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 100,
|
height: 100,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: CircularProgressIndicator(),
|
child: Lottie.asset(
|
||||||
|
'assets/loading.json',
|
||||||
|
width: 200,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -595,8 +599,4 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Widget StaffPanel(BuildContext context, videoIntroController) {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,7 +29,7 @@ class _FavPanelState extends State<FavPanel> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
height: sheetHeight,
|
height: sheetHeight,
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
AppBar(
|
AppBar(
|
||||||
|
|||||||
@ -57,7 +57,7 @@ class _GroupPanelState extends State<GroupPanel> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
height: sheetHeight,
|
height: sheetHeight,
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
AppBar(
|
AppBar(
|
||||||
|
|||||||
@ -12,7 +12,7 @@ class MenuRow extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
padding: const EdgeInsets.only(top: 9, bottom: 9, left: 12),
|
padding: const EdgeInsets.only(top: 9, bottom: 9, left: 12),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
@ -84,7 +84,7 @@ class MenuRow extends StatelessWidget {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
color: selectStatus
|
color: selectStatus
|
||||||
? Theme.of(context).colorScheme.onBackground
|
? Theme.of(context).colorScheme.onSurface
|
||||||
: Theme.of(context).colorScheme.outline),
|
: Theme.of(context).colorScheme.outline),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import 'package:easy_debounce/easy_throttle.dart';
|
import 'package:easy_debounce/easy_throttle.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:pilipala/http/reply.dart';
|
import 'package:pilipala/http/reply.dart';
|
||||||
@ -15,7 +14,6 @@ class VideoReplyController extends GetxController {
|
|||||||
this.rpid,
|
this.rpid,
|
||||||
this.replyLevel,
|
this.replyLevel,
|
||||||
);
|
);
|
||||||
final ScrollController scrollController = ScrollController();
|
|
||||||
// 视频aid 请求时使用的oid
|
// 视频aid 请求时使用的oid
|
||||||
int? aid;
|
int? aid;
|
||||||
// 层级 2为楼中楼
|
// 层级 2为楼中楼
|
||||||
|
|||||||
@ -67,13 +67,12 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
|
|||||||
vsync: this, duration: const Duration(milliseconds: 300));
|
vsync: this, duration: const Duration(milliseconds: 300));
|
||||||
|
|
||||||
_futureBuilderFuture = _videoReplyController.queryReplyList();
|
_futureBuilderFuture = _videoReplyController.queryReplyList();
|
||||||
|
scrollController = ScrollController();
|
||||||
fabAnimationCtr.forward();
|
fabAnimationCtr.forward();
|
||||||
scrollListener();
|
scrollListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
void scrollListener() {
|
void scrollListener() {
|
||||||
scrollController = _videoReplyController.scrollController;
|
|
||||||
scrollController.addListener(
|
scrollController.addListener(
|
||||||
() {
|
() {
|
||||||
if (scrollController.position.pixels >=
|
if (scrollController.position.pixels >=
|
||||||
@ -185,7 +184,8 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
|
|||||||
builder: (BuildContext context, snapshot) {
|
builder: (BuildContext context, snapshot) {
|
||||||
if (snapshot.connectionState == ConnectionState.done) {
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
var data = snapshot.data;
|
var data = snapshot.data;
|
||||||
if (data['status']) {
|
if (_videoReplyController.replyList.isNotEmpty ||
|
||||||
|
(data && data['status'])) {
|
||||||
// 请求成功
|
// 请求成功
|
||||||
return Obx(
|
return Obx(
|
||||||
() => _videoReplyController.isLoadingMore &&
|
() => _videoReplyController.isLoadingMore &&
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:appscheme/appscheme.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
@ -11,6 +12,7 @@ import 'package:pilipala/models/video/reply/item.dart';
|
|||||||
import 'package:pilipala/pages/preview/index.dart';
|
import 'package:pilipala/pages/preview/index.dart';
|
||||||
import 'package:pilipala/pages/video/detail/index.dart';
|
import 'package:pilipala/pages/video/detail/index.dart';
|
||||||
import 'package:pilipala/pages/video/detail/reply_new/index.dart';
|
import 'package:pilipala/pages/video/detail/reply_new/index.dart';
|
||||||
|
import 'package:pilipala/utils/app_scheme.dart';
|
||||||
import 'package:pilipala/utils/feed_back.dart';
|
import 'package:pilipala/utils/feed_back.dart';
|
||||||
import 'package:pilipala/utils/id_utils.dart';
|
import 'package:pilipala/utils/id_utils.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
@ -643,34 +645,17 @@ InlineSpan buildContent(
|
|||||||
'',
|
'',
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
final String pathSegment = Uri.parse(matchStr).path;
|
Uri uri = Uri.parse(matchStr);
|
||||||
Map matchRes = IdUtils.matchAvorBv(input: pathSegment);
|
SchemeEntity scheme = SchemeEntity(
|
||||||
List matchKeys = matchRes.keys.toList();
|
scheme: uri.scheme,
|
||||||
if (matchKeys.isNotEmpty) {
|
host: uri.host,
|
||||||
UrlUtils.matchUrlPush(
|
port: uri.port,
|
||||||
matchRes.containsKey('AV')
|
path: uri.path,
|
||||||
? matchRes['AV']! as int
|
query: uri.queryParameters,
|
||||||
: matchRes['BV'],
|
source: '',
|
||||||
title,
|
dataString: matchStr,
|
||||||
matchStr,
|
|
||||||
);
|
);
|
||||||
} else {
|
PiliSchame.fullPathPush(scheme);
|
||||||
final String redirectUrl =
|
|
||||||
await UrlUtils.parseRedirectUrl(matchStr);
|
|
||||||
// if (redirectUrl == matchStr) {
|
|
||||||
// Clipboard.setData(ClipboardData(text: matchStr));
|
|
||||||
// SmartDialog.showToast('地址可能有误');
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
Get.toNamed(
|
|
||||||
'/webview',
|
|
||||||
parameters: {
|
|
||||||
'url': redirectUrl,
|
|
||||||
'type': 'url',
|
|
||||||
'pageTitle': title
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (appUrlSchema.startsWith('bilibili://search')) {
|
if (appUrlSchema.startsWith('bilibili://search')) {
|
||||||
|
|||||||
@ -170,7 +170,7 @@ class _VideoReplyNewDialogState extends State<VideoReplyNewDialog>
|
|||||||
topLeft: Radius.circular(12),
|
topLeft: Radius.circular(12),
|
||||||
topRight: Radius.circular(12),
|
topRight: Radius.circular(12),
|
||||||
),
|
),
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
|||||||
@ -78,7 +78,7 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
height: widget.source == 'videoDetail' ? widget.sheetHeight : null,
|
height: widget.source == 'videoDetail' ? widget.sheetHeight : null,
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
if (widget.source == 'videoDetail')
|
if (widget.source == 'videoDetail')
|
||||||
|
|||||||
@ -99,7 +99,6 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
fullScreenStatusListener();
|
fullScreenStatusListener();
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
floating = vdCtr.floating!;
|
floating = vdCtr.floating!;
|
||||||
autoEnterPip();
|
|
||||||
}
|
}
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
lifecycleListener();
|
lifecycleListener();
|
||||||
@ -128,8 +127,9 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 播放器状态监听
|
// 播放器状态监听
|
||||||
void playerListener(PlayerStatus? status) async {
|
void playerListener(PlayerStatus status) async {
|
||||||
playerStatus.value = status!;
|
playerStatus.value = status;
|
||||||
|
autoEnterPip(status: status);
|
||||||
if (status == PlayerStatus.completed) {
|
if (status == PlayerStatus.completed) {
|
||||||
// 结束播放退出全屏
|
// 结束播放退出全屏
|
||||||
if (autoExitFullcreen) {
|
if (autoExitFullcreen) {
|
||||||
@ -176,11 +176,12 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
|
|
||||||
/// 未开启自动播放时触发播放
|
/// 未开启自动播放时触发播放
|
||||||
Future<void> handlePlay() async {
|
Future<void> handlePlay() async {
|
||||||
await vdCtr.playerInit();
|
await vdCtr.playerInit(autoplay: true);
|
||||||
plPlayerController = vdCtr.plPlayerController;
|
plPlayerController = vdCtr.plPlayerController;
|
||||||
plPlayerController!.addStatusLister(playerListener);
|
plPlayerController!.addStatusLister(playerListener);
|
||||||
vdCtr.autoPlay.value = true;
|
vdCtr.autoPlay.value = true;
|
||||||
vdCtr.isShowCover.value = false;
|
vdCtr.isShowCover.value = false;
|
||||||
|
autoEnterPip(status: PlayerStatus.playing);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fullScreenStatusListener() {
|
void fullScreenStatusListener() {
|
||||||
@ -266,7 +267,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
}
|
}
|
||||||
vdCtr.isFirstTime = false;
|
vdCtr.isFirstTime = false;
|
||||||
final bool autoplay = autoPlayEnable;
|
final bool autoplay = autoPlayEnable;
|
||||||
vdCtr.playerInit(autoplay: autoplay);
|
vdCtr.playerInit();
|
||||||
|
|
||||||
/// 未开启自动播放时,未播放跳转下一页返回/播放后跳转下一页返回
|
/// 未开启自动播放时,未播放跳转下一页返回/播放后跳转下一页返回
|
||||||
vdCtr.autoPlay.value = !vdCtr.isShowCover.value;
|
vdCtr.autoPlay.value = !vdCtr.isShowCover.value;
|
||||||
@ -287,10 +288,12 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
.subscribe(this, ModalRoute.of(context)! as PageRoute);
|
.subscribe(this, ModalRoute.of(context)! as PageRoute);
|
||||||
}
|
}
|
||||||
|
|
||||||
void autoEnterPip() {
|
void autoEnterPip({PlayerStatus? status}) {
|
||||||
final String routePath = Get.currentRoute;
|
final String routePath = Get.currentRoute;
|
||||||
if (autoPiP && routePath.startsWith('/video')) {
|
if (autoPiP && routePath.startsWith('/video')) {
|
||||||
floating.toggleAutoPip(autoEnter: autoPiP);
|
floating.toggleAutoPip(
|
||||||
|
autoEnter: autoPiP && status == PlayerStatus.playing,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,6 +317,15 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
case 'show' || 'restart':
|
case 'show' || 'restart':
|
||||||
plPlayerController?.danmakuController?.clear();
|
plPlayerController?.danmakuController?.clear();
|
||||||
break;
|
break;
|
||||||
|
case 'pause':
|
||||||
|
vdCtr.hiddenReplyReplyPanel();
|
||||||
|
if (vdCtr.videoType == SearchType.video) {
|
||||||
|
videoIntroController.hiddenEpisodeBottomSheet();
|
||||||
|
}
|
||||||
|
if (vdCtr.videoType == SearchType.media_bangumi) {
|
||||||
|
bangumiIntroController.hiddenEpisodeBottomSheet();
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -525,11 +537,10 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
Scaffold(
|
Scaffold(
|
||||||
resizeToAvoidBottomInset: false,
|
resizeToAvoidBottomInset: false,
|
||||||
key: vdCtr.scaffoldKey,
|
key: vdCtr.scaffoldKey,
|
||||||
backgroundColor: Colors.black,
|
|
||||||
appBar: PreferredSize(
|
appBar: PreferredSize(
|
||||||
preferredSize: const Size.fromHeight(0),
|
preferredSize: const Size.fromHeight(0),
|
||||||
child: AppBar(
|
child: AppBar(
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.black,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -559,8 +570,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
}
|
}
|
||||||
return SliverAppBar(
|
return SliverAppBar(
|
||||||
automaticallyImplyLeading: false,
|
automaticallyImplyLeading: false,
|
||||||
// 假装使用一个非空变量,避免Obx检测不到而罢工
|
pinned: true,
|
||||||
pinned: vdCtr.autoPlay.value,
|
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
scrolledUnderElevation: 0,
|
scrolledUnderElevation: 0,
|
||||||
forceElevated: innerBoxIsScrolled,
|
forceElevated: innerBoxIsScrolled,
|
||||||
@ -568,8 +578,8 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
backgroundColor: Colors.black,
|
backgroundColor: Colors.black,
|
||||||
flexibleSpace: FlexibleSpaceBar(
|
flexibleSpace: FlexibleSpaceBar(
|
||||||
background: PopScope(
|
background: PopScope(
|
||||||
canPop: plPlayerController?.isFullScreen.value !=
|
canPop:
|
||||||
true,
|
plPlayerController?.isFullScreen.value != true,
|
||||||
onPopInvoked: (bool didPop) {
|
onPopInvoked: (bool didPop) {
|
||||||
if (plPlayerController?.isFullScreen.value ==
|
if (plPlayerController?.isFullScreen.value ==
|
||||||
true) {
|
true) {
|
||||||
@ -581,16 +591,11 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
verticalScreen();
|
verticalScreen();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: LayoutBuilder(
|
child: Hero(
|
||||||
builder: (BuildContext context,
|
tag: heroTag,
|
||||||
BoxConstraints boxConstraints) {
|
child: Stack(
|
||||||
return Stack(
|
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
if (isShowing)
|
if (isShowing) videoPlayerPanel,
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.only(top: 0),
|
|
||||||
child: videoPlayerPanel,
|
|
||||||
),
|
|
||||||
|
|
||||||
/// 关闭自动播放时 手动播放
|
/// 关闭自动播放时 手动播放
|
||||||
Obx(
|
Obx(
|
||||||
@ -606,9 +611,9 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
),
|
||||||
},
|
),
|
||||||
)),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -627,10 +632,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
: pinnedHeaderHeight;
|
: pinnedHeaderHeight;
|
||||||
},
|
},
|
||||||
onlyOneScrollInBody: true,
|
onlyOneScrollInBody: true,
|
||||||
body: ColoredBox(
|
body: Column(
|
||||||
key: Key(heroTag),
|
|
||||||
color: Theme.of(context).colorScheme.background,
|
|
||||||
child: Column(
|
|
||||||
children: [
|
children: [
|
||||||
tabbarBuild(),
|
tabbarBuild(),
|
||||||
Expanded(
|
Expanded(
|
||||||
@ -646,8 +648,8 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
VideoIntroPanel(bvid: vdCtr.bvid),
|
VideoIntroPanel(bvid: vdCtr.bvid),
|
||||||
] else if (vdCtr.videoType ==
|
] else if (vdCtr.videoType ==
|
||||||
SearchType.media_bangumi) ...[
|
SearchType.media_bangumi) ...[
|
||||||
Obx(() => BangumiIntroPanel(
|
Obx(() =>
|
||||||
cid: vdCtr.cid.value)),
|
BangumiIntroPanel(cid: vdCtr.cid.value)),
|
||||||
],
|
],
|
||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: Divider(
|
child: Divider(
|
||||||
@ -678,7 +680,6 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
|
|
||||||
/// 重新进入会刷新
|
/// 重新进入会刷新
|
||||||
// 播放完成/暂停播放
|
// 播放完成/暂停播放
|
||||||
|
|||||||
@ -23,7 +23,7 @@ class AiDetail extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
sheetHeight = localCache.get('sheetHeight');
|
sheetHeight = localCache.get('sheetHeight');
|
||||||
return Container(
|
return Container(
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
padding: const EdgeInsets.only(left: 14, right: 14),
|
padding: const EdgeInsets.only(left: 14, right: 14),
|
||||||
height: sheetHeight,
|
height: sheetHeight,
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|||||||
@ -29,7 +29,7 @@ class ScrollAppBar extends StatelessWidget {
|
|||||||
opacity: scrollDistance / (videoHeight - kToolbarHeight),
|
opacity: scrollDistance / (videoHeight - kToolbarHeight),
|
||||||
child: Container(
|
child: Container(
|
||||||
height: statusBarHeight + kToolbarHeight,
|
height: statusBarHeight + kToolbarHeight,
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
padding: EdgeInsets.only(top: statusBarHeight),
|
padding: EdgeInsets.only(top: statusBarHeight),
|
||||||
child: AppBar(
|
child: AppBar(
|
||||||
primary: false,
|
primary: false,
|
||||||
|
|||||||
@ -93,7 +93,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
height: 460,
|
height: 460,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
||||||
),
|
),
|
||||||
margin: const EdgeInsets.all(12),
|
margin: const EdgeInsets.all(12),
|
||||||
@ -317,7 +317,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
height: 500,
|
height: 500,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
||||||
),
|
),
|
||||||
margin: const EdgeInsets.all(12),
|
margin: const EdgeInsets.all(12),
|
||||||
@ -377,7 +377,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
inactiveThumbColor:
|
inactiveThumbColor:
|
||||||
Theme.of(context).colorScheme.primaryContainer,
|
Theme.of(context).colorScheme.primaryContainer,
|
||||||
inactiveTrackColor:
|
inactiveTrackColor:
|
||||||
Theme.of(context).colorScheme.background,
|
Theme.of(context).colorScheme.surface,
|
||||||
splashRadius: 10.0,
|
splashRadius: 10.0,
|
||||||
// boolean variable value
|
// boolean variable value
|
||||||
value: shutdownTimerService.waitForPlayingCompleted,
|
value: shutdownTimerService.waitForPlayingCompleted,
|
||||||
@ -570,7 +570,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
height: 310,
|
height: 310,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
||||||
),
|
),
|
||||||
margin: const EdgeInsets.all(12),
|
margin: const EdgeInsets.all(12),
|
||||||
@ -660,7 +660,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
height: 250,
|
height: 250,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
||||||
),
|
),
|
||||||
margin: const EdgeInsets.all(12),
|
margin: const EdgeInsets.all(12),
|
||||||
@ -734,7 +734,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
height: 250,
|
height: 250,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
||||||
),
|
),
|
||||||
margin: const EdgeInsets.all(12),
|
margin: const EdgeInsets.all(12),
|
||||||
@ -828,7 +828,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
height: 580,
|
height: 580,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
||||||
),
|
),
|
||||||
margin: const EdgeInsets.all(12),
|
margin: const EdgeInsets.all(12),
|
||||||
@ -1084,7 +1084,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
height: 250,
|
height: 250,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
||||||
),
|
),
|
||||||
margin: const EdgeInsets.all(12),
|
margin: const EdgeInsets.all(12),
|
||||||
|
|||||||
@ -76,7 +76,7 @@ class WebviewController extends GetxController {
|
|||||||
(url.startsWith(
|
(url.startsWith(
|
||||||
'https://passport.bilibili.com/web/sso/exchange_cookie') ||
|
'https://passport.bilibili.com/web/sso/exchange_cookie') ||
|
||||||
url.startsWith('https://m.bilibili.com/'))) {
|
url.startsWith('https://m.bilibili.com/'))) {
|
||||||
confirmLogin(url);
|
LoginUtils.confirmLogin(url, controller);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onWebResourceError: (WebResourceError error) {},
|
onWebResourceError: (WebResourceError error) {},
|
||||||
@ -97,51 +97,4 @@ class WebviewController extends GetxController {
|
|||||||
)
|
)
|
||||||
..loadRequest(Uri.parse(url));
|
..loadRequest(Uri.parse(url));
|
||||||
}
|
}
|
||||||
|
|
||||||
confirmLogin(url) async {
|
|
||||||
var content = '';
|
|
||||||
if (url != null) {
|
|
||||||
content = '${content + url}; \n';
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
await SetCookie.onSet();
|
|
||||||
final result = await UserHttp.userInfo();
|
|
||||||
if (result['status'] && result['data'].isLogin) {
|
|
||||||
SmartDialog.showToast('登录成功');
|
|
||||||
try {
|
|
||||||
Box userInfoCache = GStrorage.userInfo;
|
|
||||||
await userInfoCache.put('userInfoCache', result['data']);
|
|
||||||
|
|
||||||
final HomeController homeCtr = Get.find<HomeController>();
|
|
||||||
homeCtr.updateLoginStatus(true);
|
|
||||||
homeCtr.userFace.value = result['data'].face;
|
|
||||||
final MediaController mediaCtr = Get.find<MediaController>();
|
|
||||||
mediaCtr.mid = result['data'].mid;
|
|
||||||
await LoginUtils.refreshLoginStatus(true);
|
|
||||||
} catch (err) {
|
|
||||||
SmartDialog.show(builder: (BuildContext context) {
|
|
||||||
return AlertDialog(
|
|
||||||
title: const Text('登录遇到问题'),
|
|
||||||
content: Text(err.toString()),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => controller.reload(),
|
|
||||||
child: const Text('确认'),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Get.back();
|
|
||||||
} else {
|
|
||||||
// 获取用户信息失败
|
|
||||||
SmartDialog.showToast(result['msg']);
|
|
||||||
Clipboard.setData(ClipboardData(text: result['msg']));
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
SmartDialog.showNotify(msg: e.toString(), notifyType: NotifyType.warning);
|
|
||||||
content = content + e.toString();
|
|
||||||
Clipboard.setData(ClipboardData(text: content));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pilipala/utils/login.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
import 'controller.dart';
|
import 'controller.dart';
|
||||||
import 'package:webview_flutter/webview_flutter.dart';
|
import 'package:webview_flutter/webview_flutter.dart';
|
||||||
@ -43,7 +44,8 @@ class _WebviewPageState extends State<WebviewPage> {
|
|||||||
Obx(
|
Obx(
|
||||||
() => _webviewController.type.value == 'login'
|
() => _webviewController.type.value == 'login'
|
||||||
? TextButton(
|
? TextButton(
|
||||||
onPressed: () => _webviewController.confirmLogin(null),
|
onPressed: () =>
|
||||||
|
LoginUtils.confirmLogin(null, _webviewController),
|
||||||
child: const Text('刷新登录状态'),
|
child: const Text('刷新登录状态'),
|
||||||
)
|
)
|
||||||
: const SizedBox(),
|
: const SizedBox(),
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
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:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pilipala/common/skeleton/skeleton.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
import 'package:pilipala/utils/utils.dart';
|
import 'package:pilipala/utils/utils.dart';
|
||||||
|
|
||||||
@ -102,9 +103,7 @@ class _WhisperPageState extends State<WhisperPage> {
|
|||||||
},
|
},
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
controller: _scrollController,
|
controller: _scrollController,
|
||||||
child: Column(
|
child: FutureBuilder(
|
||||||
children: [
|
|
||||||
FutureBuilder(
|
|
||||||
future: _futureBuilderFuture,
|
future: _futureBuilderFuture,
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.connectionState == ConnectionState.done) {
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
@ -117,93 +116,12 @@ class _WhisperPageState extends State<WhisperPage> {
|
|||||||
: ListView.separated(
|
: ListView.separated(
|
||||||
itemCount: sessionList.length,
|
itemCount: sessionList.length,
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
physics:
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
const NeverScrollableScrollPhysics(),
|
|
||||||
itemBuilder: (_, int i) {
|
itemBuilder: (_, int i) {
|
||||||
return ListTile(
|
return SessionItem(
|
||||||
onTap: () {
|
sessionItem: sessionList[i],
|
||||||
sessionList[i].unreadCount = 0;
|
changeFucCall: () =>
|
||||||
sessionList.refresh();
|
sessionList.refresh(),
|
||||||
Get.toNamed(
|
|
||||||
'/whisperDetail',
|
|
||||||
parameters: {
|
|
||||||
'talkerId': sessionList[i]
|
|
||||||
.talkerId
|
|
||||||
.toString(),
|
|
||||||
'name': sessionList[i]
|
|
||||||
.accountInfo
|
|
||||||
.name,
|
|
||||||
'face': sessionList[i]
|
|
||||||
.accountInfo
|
|
||||||
.face,
|
|
||||||
'mid': sessionList[i]
|
|
||||||
.accountInfo
|
|
||||||
.mid
|
|
||||||
.toString(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
leading: Badge(
|
|
||||||
isLabelVisible:
|
|
||||||
sessionList[i].unreadCount > 0,
|
|
||||||
label: Text(sessionList[i]
|
|
||||||
.unreadCount
|
|
||||||
.toString()),
|
|
||||||
alignment: Alignment.topRight,
|
|
||||||
child: NetworkImgLayer(
|
|
||||||
width: 45,
|
|
||||||
height: 45,
|
|
||||||
type: 'avatar',
|
|
||||||
src: sessionList[i]
|
|
||||||
.accountInfo
|
|
||||||
.face,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
sessionList[i].accountInfo.name),
|
|
||||||
subtitle: Text(
|
|
||||||
sessionList[i].lastMsg.content !=
|
|
||||||
null &&
|
|
||||||
sessionList[i]
|
|
||||||
.lastMsg
|
|
||||||
.content !=
|
|
||||||
''
|
|
||||||
? (sessionList[i]
|
|
||||||
.lastMsg
|
|
||||||
.content['text'] ??
|
|
||||||
sessionList[i]
|
|
||||||
.lastMsg
|
|
||||||
.content['content'] ??
|
|
||||||
sessionList[i]
|
|
||||||
.lastMsg
|
|
||||||
.content['title'] ??
|
|
||||||
sessionList[i]
|
|
||||||
.lastMsg
|
|
||||||
.content[
|
|
||||||
'reply_content'] ??
|
|
||||||
'不支持的消息类型')
|
|
||||||
: '不支持的消息类型',
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.labelMedium!
|
|
||||||
.copyWith(
|
|
||||||
color: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.outline)),
|
|
||||||
trailing: Text(
|
|
||||||
Utils.dateFormat(sessionList[i]
|
|
||||||
.lastMsg
|
|
||||||
.timestamp),
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.labelSmall!
|
|
||||||
.copyWith(
|
|
||||||
color: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.outline),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
separatorBuilder:
|
separatorBuilder:
|
||||||
@ -225,11 +143,43 @@ class _WhisperPageState extends State<WhisperPage> {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 骨架屏
|
// 骨架屏
|
||||||
return const SizedBox();
|
return ListView.builder(
|
||||||
|
itemCount: 15,
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
itemBuilder: (context, int i) {
|
||||||
|
return Skeleton(
|
||||||
|
child: ListTile(
|
||||||
|
leading: Container(
|
||||||
|
width: 45,
|
||||||
|
height: 45,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onInverseSurface,
|
||||||
|
borderRadius: BorderRadius.circular(25),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
title: Container(
|
||||||
|
width: 100,
|
||||||
|
height: 14,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onInverseSurface,
|
||||||
|
),
|
||||||
|
subtitle: Container(
|
||||||
|
width: 80,
|
||||||
|
height: 14,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onInverseSurface,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -239,3 +189,67 @@ class _WhisperPageState extends State<WhisperPage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SessionItem extends StatelessWidget {
|
||||||
|
final dynamic sessionItem;
|
||||||
|
final Function changeFucCall;
|
||||||
|
|
||||||
|
const SessionItem({
|
||||||
|
super.key,
|
||||||
|
required this.sessionItem,
|
||||||
|
required this.changeFucCall,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final content = sessionItem.lastMsg.content;
|
||||||
|
return ListTile(
|
||||||
|
onTap: () {
|
||||||
|
sessionItem.unreadCount = 0;
|
||||||
|
changeFucCall.call();
|
||||||
|
Get.toNamed(
|
||||||
|
'/whisperDetail',
|
||||||
|
parameters: {
|
||||||
|
'talkerId': sessionItem.talkerId.toString(),
|
||||||
|
'name': sessionItem.accountInfo.name,
|
||||||
|
'face': sessionItem.accountInfo.face,
|
||||||
|
'mid': sessionItem.accountInfo.mid.toString(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
leading: Badge(
|
||||||
|
isLabelVisible: sessionItem.unreadCount > 0,
|
||||||
|
label: Text(sessionItem.unreadCount.toString()),
|
||||||
|
alignment: Alignment.topRight,
|
||||||
|
child: NetworkImgLayer(
|
||||||
|
width: 45,
|
||||||
|
height: 45,
|
||||||
|
type: 'avatar',
|
||||||
|
src: sessionItem.accountInfo.face,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
title: Text(sessionItem.accountInfo.name),
|
||||||
|
subtitle: Text(
|
||||||
|
content != null && content != ''
|
||||||
|
? (content['text'] ??
|
||||||
|
content['content'] ??
|
||||||
|
content['title'] ??
|
||||||
|
content['reply_content'] ??
|
||||||
|
'不支持的消息类型')
|
||||||
|
: '不支持的消息类型',
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.labelMedium!
|
||||||
|
.copyWith(color: Theme.of(context).colorScheme.outline)),
|
||||||
|
trailing: Text(
|
||||||
|
Utils.dateFormat(sessionItem.lastMsg.timestamp),
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.labelSmall!
|
||||||
|
.copyWith(color: Theme.of(context).colorScheme.outline),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -267,11 +267,8 @@ class ChatItem extends StatelessWidget {
|
|||||||
.colorScheme
|
.colorScheme
|
||||||
.secondaryContainer
|
.secondaryContainer
|
||||||
.withOpacity(0.4),
|
.withOpacity(0.4),
|
||||||
borderRadius: const BorderRadius.only(
|
borderRadius: const BorderRadius.all(
|
||||||
topLeft: Radius.circular(16),
|
Radius.circular(16),
|
||||||
topRight: Radius.circular(16),
|
|
||||||
bottomLeft: Radius.circular(6),
|
|
||||||
bottomRight: Radius.circular(16),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
margin: const EdgeInsets.all(12),
|
margin: const EdgeInsets.all(12),
|
||||||
@ -292,8 +289,8 @@ class ChatItem extends StatelessWidget {
|
|||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
RegExp bvRegex = RegExp(r'BV[0-9A-Za-z]{10}',
|
RegExp bvRegex =
|
||||||
caseSensitive: false);
|
RegExp(r'BV[0-9A-Za-z]{10}', caseSensitive: false);
|
||||||
Iterable<Match> matches =
|
Iterable<Match> matches =
|
||||||
bvRegex.allMatches(i['jump_url']);
|
bvRegex.allMatches(i['jump_url']);
|
||||||
if (matches.isNotEmpty) {
|
if (matches.isNotEmpty) {
|
||||||
@ -353,7 +350,7 @@ class ChatItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
Utils.timeFormat(int.parse(i['field3'])),
|
i['field3'],
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
letterSpacing: 0.6,
|
letterSpacing: 0.6,
|
||||||
height: 1.5,
|
height: 1.5,
|
||||||
@ -364,10 +361,12 @@ class ChatItem extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
],
|
],
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
));
|
),
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return Text(
|
return Text(
|
||||||
content != null && content != ''
|
content != null && content != ''
|
||||||
|
|||||||
@ -123,6 +123,7 @@ class PlPlayerController {
|
|||||||
PreferredSizeWidget? bottomControl;
|
PreferredSizeWidget? bottomControl;
|
||||||
Widget? danmuWidget;
|
Widget? danmuWidget;
|
||||||
late RxList subtitles;
|
late RxList subtitles;
|
||||||
|
String videoType = 'archive';
|
||||||
|
|
||||||
/// 数据加载监听
|
/// 数据加载监听
|
||||||
Stream<DataStatus> get onDataStatusChanged => dataStatus.status.stream;
|
Stream<DataStatus> get onDataStatusChanged => dataStatus.status.stream;
|
||||||
@ -220,7 +221,7 @@ class PlPlayerController {
|
|||||||
Rx<int> get playerCount => _playerCount;
|
Rx<int> get playerCount => _playerCount;
|
||||||
|
|
||||||
///
|
///
|
||||||
Rx<String> get videoType => _videoType;
|
// Rx<String> get videoType => _videoType;
|
||||||
|
|
||||||
/// 弹幕开关
|
/// 弹幕开关
|
||||||
Rx<bool> isOpenDanmu = false.obs;
|
Rx<bool> isOpenDanmu = false.obs;
|
||||||
@ -274,8 +275,7 @@ class PlPlayerController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 添加一个私有构造函数
|
// 添加一个私有构造函数
|
||||||
PlPlayerController._() {
|
PlPlayerController._internal(this.videoType) {
|
||||||
_videoType = videoType;
|
|
||||||
isOpenDanmu.value =
|
isOpenDanmu.value =
|
||||||
setting.get(SettingBoxKey.enableShowDanmaku, defaultValue: false);
|
setting.get(SettingBoxKey.enableShowDanmaku, defaultValue: false);
|
||||||
blockTypes =
|
blockTypes =
|
||||||
@ -330,11 +330,11 @@ class PlPlayerController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取实例 传参
|
// 获取实例 传参
|
||||||
static PlPlayerController getInstance({
|
factory PlPlayerController({
|
||||||
String videoType = 'archive',
|
String videoType = 'archive',
|
||||||
}) {
|
}) {
|
||||||
// 如果实例尚未创建,则创建一个新实例
|
// 如果实例尚未创建,则创建一个新实例
|
||||||
_instance ??= PlPlayerController._();
|
_instance ??= PlPlayerController._internal(videoType);
|
||||||
if (videoType != 'none') {
|
if (videoType != 'none') {
|
||||||
_instance!._playerCount.value += 1;
|
_instance!._playerCount.value += 1;
|
||||||
_videoType.value = videoType;
|
_videoType.value = videoType;
|
||||||
@ -406,7 +406,7 @@ class PlPlayerController {
|
|||||||
if (!_listenersInitialized) {
|
if (!_listenersInitialized) {
|
||||||
startListeners();
|
startListeners();
|
||||||
}
|
}
|
||||||
await _initializePlayer(seekTo: seekTo, duration: _duration.value);
|
await _initializePlayer(duration: _duration.value);
|
||||||
bool autoEnterFullcreen =
|
bool autoEnterFullcreen =
|
||||||
setting.get(SettingBoxKey.enableAutoEnter, defaultValue: false);
|
setting.get(SettingBoxKey.enableAutoEnter, defaultValue: false);
|
||||||
if (autoEnterFullcreen && _isFirstTime) {
|
if (autoEnterFullcreen && _isFirstTime) {
|
||||||
@ -443,7 +443,7 @@ class PlPlayerController {
|
|||||||
configuration: PlayerConfiguration(
|
configuration: PlayerConfiguration(
|
||||||
// 默认缓存 5M 大小
|
// 默认缓存 5M 大小
|
||||||
bufferSize:
|
bufferSize:
|
||||||
videoType.value == 'live' ? 32 * 1024 * 1024 : 5 * 1024 * 1024,
|
videoType == 'live' ? 32 * 1024 * 1024 : 5 * 1024 * 1024,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -523,7 +523,6 @@ class PlPlayerController {
|
|||||||
|
|
||||||
// 开始播放
|
// 开始播放
|
||||||
Future _initializePlayer({
|
Future _initializePlayer({
|
||||||
Duration seekTo = Duration.zero,
|
|
||||||
Duration? duration,
|
Duration? duration,
|
||||||
}) async {
|
}) async {
|
||||||
getVideoFit();
|
getVideoFit();
|
||||||
@ -542,7 +541,7 @@ class PlPlayerController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 设置倍速
|
/// 设置倍速
|
||||||
if (videoType.value == 'live') {
|
if (videoType == 'live') {
|
||||||
await setPlaybackSpeed(1.0);
|
await setPlaybackSpeed(1.0);
|
||||||
} else {
|
} else {
|
||||||
if (_playbackSpeed.value != 1.0) {
|
if (_playbackSpeed.value != 1.0) {
|
||||||
@ -934,7 +933,7 @@ class PlPlayerController {
|
|||||||
|
|
||||||
/// 设置长按倍速状态 live模式下禁用
|
/// 设置长按倍速状态 live模式下禁用
|
||||||
void setDoubleSpeedStatus(bool val) {
|
void setDoubleSpeedStatus(bool val) {
|
||||||
if (videoType.value == 'live') {
|
if (videoType == 'live') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (controlsLock.value) {
|
if (controlsLock.value) {
|
||||||
@ -1016,7 +1015,7 @@ class PlPlayerController {
|
|||||||
if (!_enableHeart) {
|
if (!_enableHeart) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (videoType.value == 'live') {
|
if (videoType == 'live') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 播放状态变化时,更新
|
// 播放状态变化时,更新
|
||||||
@ -1115,7 +1114,6 @@ class PlPlayerController {
|
|||||||
// _buffered.close();
|
// _buffered.close();
|
||||||
// _showControls.close();
|
// _showControls.close();
|
||||||
// _controlsLock.close();
|
// _controlsLock.close();
|
||||||
|
|
||||||
// playerStatus.status.close();
|
// playerStatus.status.close();
|
||||||
// dataStatus.status.close();
|
// dataStatus.status.close();
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import 'package:flutter_volume_controller/flutter_volume_controller.dart';
|
|||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:lottie/lottie.dart';
|
||||||
import 'package:media_kit/media_kit.dart';
|
import 'package:media_kit/media_kit.dart';
|
||||||
import 'package:media_kit_video/media_kit_video.dart';
|
import 'package:media_kit_video/media_kit_video.dart';
|
||||||
import 'package:pilipala/models/common/gesture_mode.dart';
|
import 'package:pilipala/models/common/gesture_mode.dart';
|
||||||
@ -652,7 +653,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
},
|
},
|
||||||
onDoubleTapDown: (TapDownDetails details) {
|
onDoubleTapDown: (TapDownDetails details) {
|
||||||
// live模式下禁用 锁定时🔒禁用
|
// live模式下禁用 锁定时🔒禁用
|
||||||
if (_.videoType.value == 'live' || _.controlsLock.value) {
|
if (_.videoType == 'live' || _.controlsLock.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final double totalWidth = MediaQuery.sizeOf(context).width;
|
final double totalWidth = MediaQuery.sizeOf(context).width;
|
||||||
@ -679,7 +680,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
/// 水平位置 快进 live模式下禁用
|
/// 水平位置 快进 live模式下禁用
|
||||||
onHorizontalDragUpdate: (DragUpdateDetails details) {
|
onHorizontalDragUpdate: (DragUpdateDetails details) {
|
||||||
// live模式下禁用 锁定时🔒禁用
|
// live模式下禁用 锁定时🔒禁用
|
||||||
if (_.videoType.value == 'live' || _.controlsLock.value) {
|
if (_.videoType == 'live' || _.controlsLock.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// final double tapPosition = details.localPosition.dx;
|
// final double tapPosition = details.localPosition.dx;
|
||||||
@ -695,7 +696,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
_.onChangedSliderStart();
|
_.onChangedSliderStart();
|
||||||
},
|
},
|
||||||
onHorizontalDragEnd: (DragEndDetails details) {
|
onHorizontalDragEnd: (DragEndDetails details) {
|
||||||
if (_.videoType.value == 'live' || _.controlsLock.value) {
|
if (_.videoType == 'live' || _.controlsLock.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_.onChangedSliderEnd();
|
_.onChangedSliderEnd();
|
||||||
@ -733,14 +734,18 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
const double threshold = 7.0; // 滑动阈值
|
const double threshold = 7.0; // 滑动阈值
|
||||||
final bool flag =
|
final bool flag =
|
||||||
fullScreenGestureMode != FullScreenGestureMode.values.last;
|
fullScreenGestureMode != FullScreenGestureMode.values.last;
|
||||||
if (dy > _distance.value && dy > threshold) {
|
if (dy > _distance.value &&
|
||||||
|
dy > threshold &&
|
||||||
|
!_.controlsLock.value) {
|
||||||
if (_.isFullScreen.value ^ flag) {
|
if (_.isFullScreen.value ^ flag) {
|
||||||
lastFullScreenToggleTime = DateTime.now();
|
lastFullScreenToggleTime = DateTime.now();
|
||||||
// 下滑退出全屏
|
// 下滑退出全屏
|
||||||
await widget.controller.triggerFullScreen(status: flag);
|
await widget.controller.triggerFullScreen(status: flag);
|
||||||
}
|
}
|
||||||
_distance.value = 0.0;
|
_distance.value = 0.0;
|
||||||
} else if (dy < _distance.value && dy < -threshold) {
|
} else if (dy < _distance.value &&
|
||||||
|
dy < -threshold &&
|
||||||
|
!_.controlsLock.value) {
|
||||||
if (!_.isFullScreen.value ^ flag) {
|
if (!_.isFullScreen.value ^ flag) {
|
||||||
lastFullScreenToggleTime = DateTime.now();
|
lastFullScreenToggleTime = DateTime.now();
|
||||||
// 上滑进入全屏
|
// 上滑进入全屏
|
||||||
@ -768,10 +773,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
),
|
),
|
||||||
|
|
||||||
// 头部、底部控制条
|
// 头部、底部控制条
|
||||||
SafeArea(
|
Obx(
|
||||||
top: false,
|
|
||||||
bottom: false,
|
|
||||||
child: Obx(
|
|
||||||
() => Column(
|
() => Column(
|
||||||
children: [
|
children: [
|
||||||
if (widget.headerControl != null || _.headerControl != null)
|
if (widget.headerControl != null || _.headerControl != null)
|
||||||
@ -800,7 +802,6 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
|
|
||||||
/// 进度条 live模式下禁用
|
/// 进度条 live模式下禁用
|
||||||
|
|
||||||
@ -826,7 +827,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_.videoType.value == 'live') {
|
if (_.videoType == 'live') {
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
if (value > max || max <= 0) {
|
if (value > max || max <= 0) {
|
||||||
@ -879,7 +880,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
// 锁
|
// 锁
|
||||||
Obx(
|
Obx(
|
||||||
() => Visibility(
|
() => Visibility(
|
||||||
visible: _.videoType.value != 'live' && _.isFullScreen.value,
|
visible: _.videoType != 'live' && _.isFullScreen.value,
|
||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: FractionalTranslation(
|
child: FractionalTranslation(
|
||||||
@ -913,9 +914,9 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
colors: [Colors.black26, Colors.transparent],
|
colors: [Colors.black26, Colors.transparent],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Image.asset(
|
child: Lottie.asset(
|
||||||
'assets/images/loading.gif',
|
'assets/loading.json',
|
||||||
height: 25,
|
width: 200,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -939,7 +940,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
begin: 0.0,
|
begin: 0.0,
|
||||||
end: _hideSeekBackwardButton.value ? 0.0 : 1.0,
|
end: _hideSeekBackwardButton.value ? 0.0 : 1.0,
|
||||||
),
|
),
|
||||||
duration: const Duration(milliseconds: 500),
|
duration: const Duration(milliseconds: 200),
|
||||||
builder: (BuildContext context, double value,
|
builder: (BuildContext context, double value,
|
||||||
Widget? child) =>
|
Widget? child) =>
|
||||||
Opacity(
|
Opacity(
|
||||||
@ -982,7 +983,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
begin: 0.0,
|
begin: 0.0,
|
||||||
end: _hideSeekForwardButton.value ? 0.0 : 1.0,
|
end: _hideSeekForwardButton.value ? 0.0 : 1.0,
|
||||||
),
|
),
|
||||||
duration: const Duration(milliseconds: 500),
|
duration: const Duration(milliseconds: 200),
|
||||||
builder: (BuildContext context, double value,
|
builder: (BuildContext context, double value,
|
||||||
Widget? child) =>
|
Widget? child) =>
|
||||||
Opacity(
|
Opacity(
|
||||||
|
|||||||
@ -29,6 +29,10 @@ class AppBarAni extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
curve: Curves.linear,
|
curve: Curves.linear,
|
||||||
)),
|
)),
|
||||||
child: Container(
|
child: Container(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
left: MediaQuery.of(context).padding.left,
|
||||||
|
right: MediaQuery.of(context).padding.right,
|
||||||
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: position! == 'top'
|
gradient: position! == 'top'
|
||||||
? const LinearGradient(
|
? const LinearGradient(
|
||||||
|
|||||||
@ -20,6 +20,13 @@ class BackwardSeekIndicatorState extends State<BackwardSeekIndicator> {
|
|||||||
|
|
||||||
Timer? timer;
|
Timer? timer;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void setState(VoidCallback fn) {
|
||||||
|
if (mounted) {
|
||||||
|
super.setState(fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import 'package:audio_video_progress_bar/audio_video_progress_bar.dart';
|
import 'package:audio_video_progress_bar/audio_video_progress_bar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:nil/nil.dart';
|
|
||||||
import 'package:pilipala/plugin/pl_player/index.dart';
|
import 'package:pilipala/plugin/pl_player/index.dart';
|
||||||
import 'package:pilipala/utils/feed_back.dart';
|
import 'package:pilipala/utils/feed_back.dart';
|
||||||
|
|
||||||
@ -36,7 +35,7 @@ class BottomControl extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
final int max = _.durationSeconds.value;
|
final int max = _.durationSeconds.value;
|
||||||
final int buffer = _.bufferedSeconds.value;
|
final int buffer = _.bufferedSeconds.value;
|
||||||
if (value > max || max <= 0) {
|
if (value > max || max <= 0) {
|
||||||
return nil;
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(left: 7, right: 7, bottom: 6),
|
padding: const EdgeInsets.only(left: 7, right: 7, bottom: 6),
|
||||||
|
|||||||
@ -20,6 +20,13 @@ class ForwardSeekIndicatorState extends State<ForwardSeekIndicator> {
|
|||||||
|
|
||||||
Timer? timer;
|
Timer? timer;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void setState(VoidCallback fn) {
|
||||||
|
if (mounted) {
|
||||||
|
super.setState(fn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|||||||
@ -26,7 +26,7 @@ class VideoPlayerServiceHandler extends BaseAudioHandler with SeekHandler {
|
|||||||
static final List<MediaItem> _item = [];
|
static final List<MediaItem> _item = [];
|
||||||
Box setting = GStrorage.setting;
|
Box setting = GStrorage.setting;
|
||||||
bool enableBackgroundPlay = false;
|
bool enableBackgroundPlay = false;
|
||||||
PlPlayerController player = PlPlayerController.getInstance();
|
PlPlayerController player = PlPlayerController();
|
||||||
|
|
||||||
VideoPlayerServiceHandler() {
|
VideoPlayerServiceHandler() {
|
||||||
revalidateSetting();
|
revalidateSetting();
|
||||||
|
|||||||
@ -18,7 +18,7 @@ class AudioSessionHandler {
|
|||||||
session.configure(const AudioSessionConfiguration.music());
|
session.configure(const AudioSessionConfiguration.music());
|
||||||
|
|
||||||
session.interruptionEventStream.listen((event) {
|
session.interruptionEventStream.listen((event) {
|
||||||
final player = PlPlayerController.getInstance(videoType: 'none');
|
final player = PlPlayerController(videoType: 'none');
|
||||||
if (event.begin) {
|
if (event.begin) {
|
||||||
if (!player.playerStatus.playing) return;
|
if (!player.playerStatus.playing) return;
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
@ -51,7 +51,7 @@ class AudioSessionHandler {
|
|||||||
|
|
||||||
// 耳机拔出暂停
|
// 耳机拔出暂停
|
||||||
session.becomingNoisyEventStream.listen((_) {
|
session.becomingNoisyEventStream.listen((_) {
|
||||||
final player = PlPlayerController.getInstance(videoType: 'none');
|
final player = PlPlayerController(videoType: 'none');
|
||||||
if (player.playerStatus.playing) {
|
if (player.playerStatus.playing) {
|
||||||
player.pause();
|
player.pause();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -89,7 +89,7 @@ class ShutdownTimerService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PlPlayerController plPlayerController =
|
PlPlayerController plPlayerController =
|
||||||
PlPlayerController.getInstance(videoType: 'none');
|
PlPlayerController(videoType: 'none');
|
||||||
if (!exitApp && !waitForPlayingCompleted) {
|
if (!exitApp && !waitForPlayingCompleted) {
|
||||||
if (!plPlayerController.playerStatus.playing) {
|
if (!plPlayerController.playerStatus.playing) {
|
||||||
//仅提示用户
|
//仅提示用户
|
||||||
@ -124,7 +124,7 @@ class ShutdownTimerService {
|
|||||||
} else {
|
} else {
|
||||||
//暂停播放
|
//暂停播放
|
||||||
PlPlayerController plPlayerController =
|
PlPlayerController plPlayerController =
|
||||||
PlPlayerController.getInstance(videoType: 'none');
|
PlPlayerController(videoType: 'none');
|
||||||
if (plPlayerController.playerStatus.playing) {
|
if (plPlayerController.playerStatus.playing) {
|
||||||
plPlayerController.pause();
|
plPlayerController.pause();
|
||||||
waitForPlayingCompleted = true;
|
waitForPlayingCompleted = true;
|
||||||
|
|||||||
@ -95,7 +95,7 @@ class PiliSchame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (scheme == 'https') {
|
if (scheme == 'https') {
|
||||||
_fullPathPush(value);
|
fullPathPush(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ class PiliSchame {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> _fullPathPush(SchemeEntity value) async {
|
static Future<void> fullPathPush(SchemeEntity value) async {
|
||||||
// https://m.bilibili.com/bangumi/play/ss39708
|
// https://m.bilibili.com/bangumi/play/ss39708
|
||||||
// https | m.bilibili.com | /bangumi/play/ss39708
|
// https | m.bilibili.com | /bangumi/play/ss39708
|
||||||
// final String scheme = value.scheme!;
|
// final String scheme = value.scheme!;
|
||||||
@ -135,8 +135,6 @@ class PiliSchame {
|
|||||||
Map<String, String>? query = value.query;
|
Map<String, String>? query = value.query;
|
||||||
RegExp regExp = RegExp(r'^((www\.)|(m\.))?bilibili\.com$');
|
RegExp regExp = RegExp(r'^((www\.)|(m\.))?bilibili\.com$');
|
||||||
if (regExp.hasMatch(host)) {
|
if (regExp.hasMatch(host)) {
|
||||||
print('bilibili.com host: $host');
|
|
||||||
print('bilibili.com path: $path');
|
|
||||||
final String lastPathSegment = path!.split('/').last;
|
final String lastPathSegment = path!.split('/').last;
|
||||||
if (path.startsWith('/video')) {
|
if (path.startsWith('/video')) {
|
||||||
Map matchRes = IdUtils.matchAvorBv(input: path);
|
Map matchRes = IdUtils.matchAvorBv(input: path);
|
||||||
@ -236,6 +234,24 @@ class PiliSchame {
|
|||||||
print('个人空间');
|
print('个人空间');
|
||||||
Get.toNamed('/member?mid=$area', arguments: {'face': ''});
|
Get.toNamed('/member?mid=$area', arguments: {'face': ''});
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
final Map<String, dynamic> map =
|
||||||
|
IdUtils.matchAvorBv(input: area.split('?').first);
|
||||||
|
if (map.containsKey('AV')) {
|
||||||
|
_videoPush(map['AV']! as int, null);
|
||||||
|
} else if (map.containsKey('BV')) {
|
||||||
|
_videoPush(null, map['BV'] as String);
|
||||||
|
} else {
|
||||||
|
Get.toNamed(
|
||||||
|
'/webview',
|
||||||
|
parameters: {
|
||||||
|
'url': value.dataString ?? "",
|
||||||
|
'type': 'url',
|
||||||
|
'pageTitle': ''
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ Future imageSaveDialog(context, videoItem, closeFn) {
|
|||||||
builder: (context) => Container(
|
builder: (context) => Container(
|
||||||
margin: const EdgeInsets.symmetric(horizontal: StyleString.safeSpace),
|
margin: const EdgeInsets.symmetric(horizontal: StyleString.safeSpace),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
borderRadius: BorderRadius.circular(10.0),
|
borderRadius: BorderRadius.circular(10.0),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|||||||
@ -2,12 +2,18 @@ import 'dart:convert';
|
|||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:crypto/crypto.dart';
|
import 'package:crypto/crypto.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:pilipala/http/user.dart';
|
||||||
import 'package:pilipala/pages/dynamics/index.dart';
|
import 'package:pilipala/pages/dynamics/index.dart';
|
||||||
import 'package:pilipala/pages/home/index.dart';
|
import 'package:pilipala/pages/home/index.dart';
|
||||||
import 'package:pilipala/pages/media/index.dart';
|
import 'package:pilipala/pages/media/index.dart';
|
||||||
import 'package:pilipala/pages/mine/index.dart';
|
import 'package:pilipala/pages/mine/index.dart';
|
||||||
|
import 'package:pilipala/utils/cookie.dart';
|
||||||
|
import 'package:pilipala/utils/storage.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
class LoginUtils {
|
class LoginUtils {
|
||||||
@ -57,4 +63,56 @@ class LoginUtils {
|
|||||||
String uuid = getUUID() + getUUID();
|
String uuid = getUUID() + getUUID();
|
||||||
return 'XY${uuid.substring(0, 35).toUpperCase()}';
|
return 'XY${uuid.substring(0, 35).toUpperCase()}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static confirmLogin(url, controller) async {
|
||||||
|
var content = '';
|
||||||
|
if (url != null) {
|
||||||
|
content = '${content + url}; \n';
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await SetCookie.onSet();
|
||||||
|
final result = await UserHttp.userInfo();
|
||||||
|
if (result['status'] && result['data'].isLogin) {
|
||||||
|
SmartDialog.showToast('登录成功');
|
||||||
|
try {
|
||||||
|
Box userInfoCache = GStrorage.userInfo;
|
||||||
|
if (!userInfoCache.isOpen) {
|
||||||
|
userInfoCache = await Hive.openBox('userInfo');
|
||||||
|
}
|
||||||
|
await userInfoCache.put('userInfoCache', result['data']);
|
||||||
|
|
||||||
|
final HomeController homeCtr = Get.find<HomeController>();
|
||||||
|
homeCtr.updateLoginStatus(true);
|
||||||
|
homeCtr.userFace.value = result['data'].face;
|
||||||
|
final MediaController mediaCtr = Get.find<MediaController>();
|
||||||
|
mediaCtr.mid = result['data'].mid;
|
||||||
|
await LoginUtils.refreshLoginStatus(true);
|
||||||
|
} catch (err) {
|
||||||
|
SmartDialog.show(builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: const Text('登录遇到问题'),
|
||||||
|
content: Text(err.toString()),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: controller != null
|
||||||
|
? () => controller.reload()
|
||||||
|
: SmartDialog.dismiss,
|
||||||
|
child: const Text('确认'),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Get.back();
|
||||||
|
} else {
|
||||||
|
// 获取用户信息失败
|
||||||
|
SmartDialog.showToast(result['msg']);
|
||||||
|
Clipboard.setData(ClipboardData(text: result['msg']));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
SmartDialog.showNotify(msg: e.toString(), notifyType: NotifyType.warning);
|
||||||
|
content = content + e.toString();
|
||||||
|
Clipboard.setData(ClipboardData(text: content));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,7 +44,7 @@ class UrlUtils {
|
|||||||
final String bv = matchRes['BV'];
|
final String bv = matchRes['BV'];
|
||||||
final Map res = await SearchHttp.ab2cWithPic(bvid: bv);
|
final Map res = await SearchHttp.ab2cWithPic(bvid: bv);
|
||||||
final int cid = res['cid'];
|
final int cid = res['cid'];
|
||||||
final String pic = res['pic'];
|
final String? pic = res['pic'];
|
||||||
final String heroTag = Utils.makeHeroTag(bv);
|
final String heroTag = Utils.makeHeroTag(bv);
|
||||||
await Get.toNamed(
|
await Get.toNamed(
|
||||||
'/video?bvid=$bv&cid=$cid',
|
'/video?bvid=$bv&cid=$cid',
|
||||||
|
|||||||
204
pubspec.lock
204
pubspec.lock
@ -17,14 +17,6 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.2.0"
|
version: "6.2.0"
|
||||||
animations:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: animations
|
|
||||||
sha256: d3d6dcfb218225bbe68e87ccf6378bbb2e32a94900722c5f81611dad089911cb
|
|
||||||
url: "https://pub.flutter-io.cn"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.11"
|
|
||||||
appscheme:
|
appscheme:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -101,10 +93,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: audio_video_progress_bar
|
name: audio_video_progress_bar
|
||||||
sha256: ccc7d7b83d2a16c52d4a7fb332faabd1baa053fb0e4c16815aefd3945ab33b81
|
sha256: "552b1f73c56c4c88407999e0a8507176f60c56de3e6d63bc20a0eab48467d4c9"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2"
|
version: "2.0.3"
|
||||||
auto_orientation:
|
auto_orientation:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -213,10 +205,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: catcher_2
|
name: catcher_2
|
||||||
sha256: "9cf33d2befd10058374e5fc6177577fdd938d73d9c06810de81cf91311a7ce98"
|
sha256: "2c2c6f8cf8c817730cd1dbb010d55292396930e7a3d42c04c3039e3fd411a2f8"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.3"
|
version: "1.2.6"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -269,10 +261,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: connectivity_plus
|
name: connectivity_plus
|
||||||
sha256: e9feae83b1849f61bad9f6f33ee00646e3410d54ce0821e02f262f9901dad3c9
|
sha256: db7a4e143dc72cc3cb2044ef9b052a7ebfe729513e6a82943bc3526f784365b8
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.1"
|
version: "6.0.3"
|
||||||
connectivity_plus_platform_interface:
|
connectivity_plus_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -301,10 +293,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: cross_file
|
name: cross_file
|
||||||
sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e
|
sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.3+8"
|
version: "0.3.4+1"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -333,10 +325,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: custom_sliding_segmented_control
|
name: custom_sliding_segmented_control
|
||||||
sha256: "05b73fa48d57218bfdf806bad68a859812b216cd81fe81c6cbefde89f39eb257"
|
sha256: "53c3e931c3ae1f696085d1ec70ac8e934da836595a9b7d9b88fdd0fcbf2a5574"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.1"
|
version: "1.8.3"
|
||||||
dart_style:
|
dart_style:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -461,10 +453,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: extended_image_library
|
name: extended_image_library
|
||||||
sha256: "9b55fc5ebc65fad984de66b8f177a1bef2a84d79203c9c213f75ff83c2c29edd"
|
sha256: c9caee8fe9b6547bd41c960c4f2d1ef8e34321804de6a1777f1d614a24247ad6
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.1"
|
version: "4.0.4"
|
||||||
extended_list:
|
extended_list:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -621,10 +613,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_volume_controller
|
name: flutter_volume_controller
|
||||||
sha256: "0f10cc759499cb6c3e152a8f6ff8e5ce385b99db7e1f586d1a29d8e6c11f4082"
|
sha256: fa4c36dfe7ef7f423704f34ab8e64e00b4a30a90aa6e56f251e9dba649efcd7f
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.1"
|
version: "1.3.2"
|
||||||
flutter_web_plugins:
|
flutter_web_plugins:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -682,10 +674,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: gt3_flutter_plugin
|
name: gt3_flutter_plugin
|
||||||
sha256: f12bff2bfbcf27467833f8d564dcc24ee2f1b3254a7c7cf5eb2c4590baf11cc1
|
sha256: "08f35692e937770ad6b3e2017eb8ef81839a82b8a63f5acf3abab14b688fc36c"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.0.8"
|
version: "0.1.0"
|
||||||
hive:
|
hive:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -722,10 +714,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139
|
sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.2"
|
version: "1.2.1"
|
||||||
http2:
|
http2:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -770,10 +762,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: intl
|
name: intl
|
||||||
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
|
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.18.1"
|
version: "0.19.0"
|
||||||
io:
|
io:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -798,6 +790,30 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.8.1"
|
version: "4.8.1"
|
||||||
|
leak_tracker:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker
|
||||||
|
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "10.0.4"
|
||||||
|
leak_tracker_flutter_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_flutter_testing
|
||||||
|
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.3"
|
||||||
|
leak_tracker_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_testing
|
||||||
|
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.1"
|
||||||
lints:
|
lints:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -834,10 +850,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: logger
|
name: logger
|
||||||
sha256: "6bbb9d6f7056729537a4309bda2e74e18e5d9f14302489cc1e93f33b3fe32cac"
|
sha256: af05cc8714f356fd1f3888fb6741cbe9fbe25cdb6eedbab80e1a6db21047d4a4
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.2+1"
|
version: "2.3.0"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -846,30 +862,38 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.2.0"
|
||||||
|
lottie:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: lottie
|
||||||
|
sha256: "6a24ade5d3d918c306bb1c21a6b9a04aab0489d51a2582522eea820b4093b62b"
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.2"
|
||||||
mailer:
|
mailer:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: mailer
|
name: mailer
|
||||||
sha256: "57f6dd1496699999a7bfd0aa6be0645384f477f4823e16d4321c40a434346382"
|
sha256: d25d89555c1031abacb448f07b801d7c01b4c21d4558e944b12b64394c84a3cb
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.1"
|
version: "6.1.0"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
|
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.16"
|
version: "0.12.16+1"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: material_color_utilities
|
name: material_color_utilities
|
||||||
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
|
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.0"
|
version: "0.8.0"
|
||||||
media_kit:
|
media_kit:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -949,26 +973,18 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
|
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.0"
|
version: "1.12.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: mime
|
name: mime
|
||||||
sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e
|
sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.5"
|
||||||
nil:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: nil
|
|
||||||
sha256: ef05770c48942876d843bf6a4822d35e5da0ff893a61f1d5ad96d15c4a659136
|
|
||||||
url: "https://pub.flutter-io.cn"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.1"
|
|
||||||
nm:
|
nm:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1022,10 +1038,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: path
|
name: path
|
||||||
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
|
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.8.3"
|
version: "1.9.0"
|
||||||
path_parsing:
|
path_parsing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1038,10 +1054,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: path_provider
|
name: path_provider
|
||||||
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
|
sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.3"
|
||||||
path_provider_android:
|
path_provider_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1054,10 +1070,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: path_provider_foundation
|
name: path_provider_foundation
|
||||||
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
|
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.1"
|
version: "2.4.0"
|
||||||
path_provider_linux:
|
path_provider_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1202,6 +1218,22 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.0"
|
version: "3.1.0"
|
||||||
|
qr:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: qr
|
||||||
|
sha256: "64957a3930367bf97cc211a5af99551d630f2f4625e38af10edd6b19131b64b3"
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.1"
|
||||||
|
qr_flutter:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: qr_flutter
|
||||||
|
sha256: "5095f0fc6e3f71d08adef8feccc8cea4f12eec18a2e31c2e8d82cb6019f4b097"
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "4.1.0"
|
||||||
rxdart:
|
rxdart:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1222,10 +1254,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: saver_gallery
|
name: saver_gallery
|
||||||
sha256: "2657953427ebe5a3b2d08157d41587c01923ccce3f1a616d55082be7470f8530"
|
sha256: "0f740608072053a0da3b19cc5812a87e36f5c3c0b959d2475c4eb3d697f4a782"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.1"
|
version: "3.0.3"
|
||||||
screen_brightness:
|
screen_brightness:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -1435,10 +1467,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.1"
|
version: "0.7.0"
|
||||||
timing:
|
timing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1467,10 +1499,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: universal_platform
|
name: universal_platform
|
||||||
sha256: d315be0f6641898b280ffa34e2ddb14f3d12b1a37882557869646e0cc363d0cc
|
sha256: "64e16458a0ea9b99260ceb5467a214c1f298d647c659af1bff6d3bf82536b1ec"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0+1"
|
version: "1.1.0"
|
||||||
uri_parser:
|
uri_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1483,10 +1515,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: url_launcher
|
name: url_launcher
|
||||||
sha256: e9aa5ea75c84cf46b3db4eea212523591211c3cf2e13099ee4ec147f54201c86
|
sha256: "6ce1e04375be4eed30548f10a315826fd933c1e493206eab82eed01f438c8d2e"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.2.2"
|
version: "6.2.6"
|
||||||
url_launcher_android:
|
url_launcher_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1499,10 +1531,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_ios
|
name: url_launcher_ios
|
||||||
sha256: bba3373219b7abb6b5e0d071b0fe66dfbe005d07517a68e38d4fc3638f35c6d3
|
sha256: "7068716403343f6ba4969b4173cbf3b84fc768042124bc2c011e5d782b24fe89"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.2.1"
|
version: "6.3.0"
|
||||||
url_launcher_linux:
|
url_launcher_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1531,10 +1563,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: url_launcher_web
|
name: url_launcher_web
|
||||||
sha256: "7286aec002c8feecc338cc33269e96b73955ab227456e9fb2a91f7fab8a358e9"
|
sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.2"
|
version: "2.3.1"
|
||||||
url_launcher_windows:
|
url_launcher_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1591,6 +1623,14 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.4.0+2"
|
version: "0.4.0+2"
|
||||||
|
vm_service:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vm_service
|
||||||
|
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "14.2.1"
|
||||||
volume_controller:
|
volume_controller:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1603,18 +1643,18 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: wakelock_plus
|
name: wakelock_plus
|
||||||
sha256: f268ca2116db22e57577fb99d52515a24bdc1d570f12ac18bb762361d43b043d
|
sha256: "104d94837bb28c735894dcd592877e990149c380e6358b00c04398ca1426eed4"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.4"
|
version: "1.2.1"
|
||||||
wakelock_plus_platform_interface:
|
wakelock_plus_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: wakelock_plus_platform_interface
|
name: wakelock_plus_platform_interface
|
||||||
sha256: "40fabed5da06caff0796dc638e1f07ee395fb18801fbff3255a2372db2d80385"
|
sha256: "582f2f7aecc7376332d961a0dd1efa9378ce117657e0ade55d9ff72699a55e82"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.2.0"
|
||||||
watcher:
|
watcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1635,10 +1675,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: web
|
name: web
|
||||||
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
|
sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.0"
|
version: "0.5.1"
|
||||||
web_socket_channel:
|
web_socket_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1659,34 +1699,34 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: webview_flutter
|
name: webview_flutter
|
||||||
sha256: d81b68e88cc353e546afb93fb38958e3717282c5ac6e5d3be4a4aef9fc3c1413
|
sha256: "6869c8786d179f929144b4a1f86e09ac0eddfe475984951ea6c634774c16b522"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.5.0"
|
version: "4.8.0"
|
||||||
webview_flutter_android:
|
webview_flutter_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: webview_flutter_android
|
name: webview_flutter_android
|
||||||
sha256: e313dcdf45d4c95bcb8960351ef2389b7f0687b90bc92483f7f7983ae5758456
|
sha256: f42447ca49523f11d8f70abea55ea211b3cafe172dd7a0e7ac007bb35dd356dc
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.13.0"
|
version: "3.16.4"
|
||||||
webview_flutter_platform_interface:
|
webview_flutter_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: webview_flutter_platform_interface
|
name: webview_flutter_platform_interface
|
||||||
sha256: "68e86162aa8fc646ae859e1585995c096c95fc2476881fa0c4a8d10f56013a5a"
|
sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.8.0"
|
version: "2.10.0"
|
||||||
webview_flutter_wkwebview:
|
webview_flutter_wkwebview:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: webview_flutter_wkwebview
|
name: webview_flutter_wkwebview
|
||||||
sha256: "4d062ad505390ecef1c4bfb6001cd857a51e00912cc9dfb66edb1886a9ebd80c"
|
sha256: "7affdf9d680c015b11587181171d3cad8093e449db1f7d9f0f08f4f33d24f9a0"
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.10.2"
|
version: "3.13.1"
|
||||||
win32:
|
win32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1728,5 +1768,5 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.2.0 <4.0.0"
|
dart: ">=3.4.0 <4.0.0"
|
||||||
flutter: ">=3.16.0"
|
flutter: ">=3.22.0"
|
||||||
|
|||||||
32
pubspec.yaml
32
pubspec.yaml
@ -44,7 +44,7 @@ dependencies:
|
|||||||
dio: ^5.4.1
|
dio: ^5.4.1
|
||||||
cookie_jar: ^4.0.8
|
cookie_jar: ^4.0.8
|
||||||
dio_cookie_manager: ^3.1.1
|
dio_cookie_manager: ^3.1.1
|
||||||
connectivity_plus: ^6.0.1
|
connectivity_plus: ^6.0.3
|
||||||
dio_http2_adapter: ^2.3.1+1
|
dio_http2_adapter: ^2.3.1+1
|
||||||
|
|
||||||
# 图片
|
# 图片
|
||||||
@ -66,7 +66,7 @@ dependencies:
|
|||||||
# cookie 管理
|
# cookie 管理
|
||||||
webview_cookie_manager: ^2.0.6
|
webview_cookie_manager: ^2.0.6
|
||||||
# 浏览器
|
# 浏览器
|
||||||
webview_flutter: ^4.5.0
|
webview_flutter: ^4.8.0
|
||||||
# 解决sliver滑动不同步
|
# 解决sliver滑动不同步
|
||||||
extended_nested_scroll_view: ^6.2.1
|
extended_nested_scroll_view: ^6.2.1
|
||||||
# 上拉加载
|
# 上拉加载
|
||||||
@ -79,7 +79,7 @@ dependencies:
|
|||||||
flutter_smart_dialog: ^4.9.4
|
flutter_smart_dialog: ^4.9.4
|
||||||
# 下滑关闭
|
# 下滑关闭
|
||||||
dismissible_page: ^1.0.2
|
dismissible_page: ^1.0.2
|
||||||
custom_sliding_segmented_control: ^1.7.5
|
custom_sliding_segmented_control: ^1.8.3
|
||||||
# 加密
|
# 加密
|
||||||
crypto: ^3.0.3
|
crypto: ^3.0.3
|
||||||
encrypt: ^5.0.3
|
encrypt: ^5.0.3
|
||||||
@ -94,19 +94,18 @@ dependencies:
|
|||||||
audio_session: ^0.1.18
|
audio_session: ^0.1.18
|
||||||
|
|
||||||
# 音量、亮度、屏幕控制
|
# 音量、亮度、屏幕控制
|
||||||
flutter_volume_controller: ^1.3.1
|
flutter_volume_controller: ^1.3.2
|
||||||
screen_brightness: ^0.2.2+1
|
screen_brightness: ^0.2.2+1
|
||||||
wakelock_plus: ^1.1.1
|
wakelock_plus: ^1.1.6
|
||||||
universal_platform: ^1.0.0+1
|
universal_platform: ^1.1.0
|
||||||
# 进度条
|
# 进度条
|
||||||
audio_video_progress_bar: ^2.0.2
|
audio_video_progress_bar: ^2.0.3
|
||||||
auto_orientation: ^2.3.1
|
auto_orientation: ^2.3.1
|
||||||
protobuf: ^3.0.0
|
protobuf: ^3.0.0
|
||||||
animations: ^2.0.11
|
|
||||||
|
|
||||||
# 获取appx信息
|
# 获取appx信息
|
||||||
package_info_plus: ^4.1.0
|
package_info_plus: ^4.2.0
|
||||||
url_launcher: ^6.1.14
|
url_launcher: ^6.2.6
|
||||||
flutter_svg: ^2.0.10+1
|
flutter_svg: ^2.0.10+1
|
||||||
# 防抖节流
|
# 防抖节流
|
||||||
easy_debounce: ^2.0.3
|
easy_debounce: ^2.0.3
|
||||||
@ -133,19 +132,21 @@ dependencies:
|
|||||||
# html渲染
|
# html渲染
|
||||||
flutter_html: ^3.0.0-beta.2
|
flutter_html: ^3.0.0-beta.2
|
||||||
# 极验
|
# 极验
|
||||||
gt3_flutter_plugin: ^0.0.8
|
gt3_flutter_plugin: ^0.1.0
|
||||||
uuid: ^3.0.7
|
uuid: ^3.0.7
|
||||||
scrollable_positioned_list: ^0.3.8
|
scrollable_positioned_list: ^0.3.8
|
||||||
nil: ^1.1.1
|
catcher_2: ^1.2.6
|
||||||
catcher_2: ^1.2.3
|
logger: ^2.3.0
|
||||||
logger: ^2.0.2+1
|
path: ^1.9.0
|
||||||
path: 1.8.3
|
|
||||||
# 电池优化
|
# 电池优化
|
||||||
disable_battery_optimization: ^1.1.1
|
disable_battery_optimization: ^1.1.1
|
||||||
# 展开/收起
|
# 展开/收起
|
||||||
expandable: ^5.0.1
|
expandable: ^5.0.1
|
||||||
# 投屏
|
# 投屏
|
||||||
dlna_dart: ^0.0.8
|
dlna_dart: ^0.0.8
|
||||||
|
lottie: ^3.1.2
|
||||||
|
# 二维码
|
||||||
|
qr_flutter: ^4.1.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@ -205,6 +206,7 @@ flutter:
|
|||||||
|
|
||||||
# To add assets to your application, add an assets section, like this:
|
# To add assets to your application, add an assets section, like this:
|
||||||
assets:
|
assets:
|
||||||
|
- assets/
|
||||||
- assets/images/
|
- assets/images/
|
||||||
- assets/images/lv/
|
- assets/images/lv/
|
||||||
- assets/images/logo/
|
- assets/images/logo/
|
||||||
|
|||||||
Reference in New Issue
Block a user