Merge branch 'design' into alpha
This commit is contained in:
@ -12,6 +12,10 @@ PODS:
|
|||||||
- FMDB (2.7.5):
|
- FMDB (2.7.5):
|
||||||
- FMDB/standard (= 2.7.5)
|
- FMDB/standard (= 2.7.5)
|
||||||
- FMDB/standard (2.7.5)
|
- FMDB/standard (2.7.5)
|
||||||
|
- gt3_flutter_plugin (0.0.8):
|
||||||
|
- Flutter
|
||||||
|
- GT3Captcha-iOS
|
||||||
|
- GT3Captcha-iOS (0.15.8.3)
|
||||||
- media_kit_libs_ios_video (1.0.4):
|
- media_kit_libs_ios_video (1.0.4):
|
||||||
- Flutter
|
- Flutter
|
||||||
- media_kit_native_event_loop (1.0.0):
|
- media_kit_native_event_loop (1.0.0):
|
||||||
@ -56,6 +60,7 @@ DEPENDENCIES:
|
|||||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||||
- Flutter (from `Flutter`)
|
- Flutter (from `Flutter`)
|
||||||
- flutter_volume_controller (from `.symlinks/plugins/flutter_volume_controller/ios`)
|
- flutter_volume_controller (from `.symlinks/plugins/flutter_volume_controller/ios`)
|
||||||
|
- gt3_flutter_plugin (from `.symlinks/plugins/gt3_flutter_plugin/ios`)
|
||||||
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
|
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
|
||||||
- media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`)
|
- media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`)
|
||||||
- media_kit_video (from `.symlinks/plugins/media_kit_video/ios`)
|
- media_kit_video (from `.symlinks/plugins/media_kit_video/ios`)
|
||||||
@ -77,6 +82,7 @@ DEPENDENCIES:
|
|||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
trunk:
|
trunk:
|
||||||
- FMDB
|
- FMDB
|
||||||
|
- GT3Captcha-iOS
|
||||||
- ReachabilitySwift
|
- ReachabilitySwift
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
EXTERNAL SOURCES:
|
||||||
@ -90,6 +96,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: Flutter
|
:path: Flutter
|
||||||
flutter_volume_controller:
|
flutter_volume_controller:
|
||||||
:path: ".symlinks/plugins/flutter_volume_controller/ios"
|
:path: ".symlinks/plugins/flutter_volume_controller/ios"
|
||||||
|
gt3_flutter_plugin:
|
||||||
|
:path: ".symlinks/plugins/gt3_flutter_plugin/ios"
|
||||||
media_kit_libs_ios_video:
|
media_kit_libs_ios_video:
|
||||||
:path: ".symlinks/plugins/media_kit_libs_ios_video/ios"
|
:path: ".symlinks/plugins/media_kit_libs_ios_video/ios"
|
||||||
media_kit_native_event_loop:
|
media_kit_native_event_loop:
|
||||||
@ -132,6 +140,8 @@ SPEC CHECKSUMS:
|
|||||||
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
|
||||||
flutter_volume_controller: e4d5832f08008180f76e30faf671ffd5a425e529
|
flutter_volume_controller: e4d5832f08008180f76e30faf671ffd5a425e529
|
||||||
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
||||||
|
gt3_flutter_plugin: bfa1f26e9a09dc00401514be5ed437f964cabf23
|
||||||
|
GT3Captcha-iOS: 5e3b1077834d8a9d6f4d64a447a30af3e14affe6
|
||||||
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
|
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
|
||||||
media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a
|
media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a
|
||||||
media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
|
media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e
|
||||||
|
@ -140,6 +140,7 @@
|
|||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
5A372F23F3CF0118D6526BAC /* [CP] Embed Pods Frameworks */,
|
5A372F23F3CF0118D6526BAC /* [CP] Embed Pods Frameworks */,
|
||||||
|
B78851E7B29A4C3961AC483C /* [CP] Copy Pods Resources */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@ -268,6 +269,23 @@
|
|||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||||
};
|
};
|
||||||
|
B78851E7B29A4C3961AC483C /* [CP] Copy Pods Resources */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
|
);
|
||||||
|
name = "[CP] Copy Pods Resources";
|
||||||
|
outputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
/* End PBXShellScriptBuildPhase section */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
@ -336,4 +336,40 @@ class Api {
|
|||||||
/// w_rid=1607c6c5a4a35a1297e31992220900ae&
|
/// w_rid=1607c6c5a4a35a1297e31992220900ae&
|
||||||
/// wts=1697033079
|
/// wts=1697033079
|
||||||
static const String aiConclusion = '/x/web-interface/view/conclusion/get';
|
static const String aiConclusion = '/x/web-interface/view/conclusion/get';
|
||||||
|
|
||||||
|
// captcha验证码
|
||||||
|
static const String getCaptcha =
|
||||||
|
'https://passport.bilibili.com/x/passport-login/captcha?source=main_web';
|
||||||
|
|
||||||
|
// web端短信验证码
|
||||||
|
static const String smsCode =
|
||||||
|
'https://passport.bilibili.com/x/passport-login/web/sms/send';
|
||||||
|
|
||||||
|
// web端验证码登录
|
||||||
|
|
||||||
|
// web端密码登录
|
||||||
|
|
||||||
|
// app端短信验证码
|
||||||
|
static const String appSmsCode =
|
||||||
|
'https://passport.bilibili.com/x/passport-login/sms/send';
|
||||||
|
|
||||||
|
// app端验证码登录
|
||||||
|
|
||||||
|
// 获取短信验证码
|
||||||
|
// static const String appSafeSmsCode =
|
||||||
|
// 'https://passport.bilibili.com/x/safecenter/common/sms/send';
|
||||||
|
|
||||||
|
/// app端密码登录
|
||||||
|
/// username
|
||||||
|
/// password
|
||||||
|
/// key
|
||||||
|
/// rhash
|
||||||
|
static const String loginInByPwdApi =
|
||||||
|
'https://passport.bilibili.com/x/passport-login/oauth2/login';
|
||||||
|
|
||||||
|
/// 密码加密密钥
|
||||||
|
/// disable_rcmd
|
||||||
|
/// local_id
|
||||||
|
static const getWebKey =
|
||||||
|
'https://passport.bilibili.com/x/passport-login/web/key';
|
||||||
}
|
}
|
||||||
|
@ -47,8 +47,8 @@ class Request {
|
|||||||
log("setCookie, ${e.toString()}");
|
log("setCookie, ${e.toString()}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setOptionsHeaders(userInfo);
|
|
||||||
}
|
}
|
||||||
|
setOptionsHeaders(userInfo, userInfo != null && userInfo.mid != null);
|
||||||
|
|
||||||
if (cookie.isEmpty) {
|
if (cookie.isEmpty) {
|
||||||
try {
|
try {
|
||||||
@ -73,8 +73,10 @@ class Request {
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
static setOptionsHeaders(userInfo) {
|
static setOptionsHeaders(userInfo, status) {
|
||||||
dio.options.headers['x-bili-mid'] = userInfo.mid.toString();
|
if (status) {
|
||||||
|
dio.options.headers['x-bili-mid'] = userInfo.mid.toString();
|
||||||
|
}
|
||||||
dio.options.headers['env'] = 'prod';
|
dio.options.headers['env'] = 'prod';
|
||||||
dio.options.headers['app-key'] = 'android64';
|
dio.options.headers['app-key'] = 'android64';
|
||||||
dio.options.headers['x-bili-aurora-eid'] = 'UlMFQVcABlAH';
|
dio.options.headers['x-bili-aurora-eid'] = 'UlMFQVcABlAH';
|
||||||
|
177
lib/http/login.dart
Normal file
177
lib/http/login.dart
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:math';
|
||||||
|
import 'package:crypto/crypto.dart';
|
||||||
|
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:encrypt/encrypt.dart';
|
||||||
|
import 'package:pilipala/http/index.dart';
|
||||||
|
import 'package:pilipala/models/login/index.dart';
|
||||||
|
import 'package:pilipala/utils/login.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
|
class LoginHttp {
|
||||||
|
static Future queryCaptcha() async {
|
||||||
|
var res = await Request().get(Api.getCaptcha);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {
|
||||||
|
'status': true,
|
||||||
|
'data': CaptchaDataModel.fromJson(res.data['data']),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {'status': false, 'data': res.message};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future sendSmsCode({
|
||||||
|
int? cid,
|
||||||
|
required int tel,
|
||||||
|
required String token,
|
||||||
|
required String challenge,
|
||||||
|
required String validate,
|
||||||
|
required String seccode,
|
||||||
|
}) async {
|
||||||
|
var res = await Request().post(
|
||||||
|
Api.appSmsCode,
|
||||||
|
data: {
|
||||||
|
'cid': cid,
|
||||||
|
'tel': tel,
|
||||||
|
"source": "main_web",
|
||||||
|
'token': token,
|
||||||
|
'challenge': challenge,
|
||||||
|
'validate': validate,
|
||||||
|
'seccode': seccode,
|
||||||
|
},
|
||||||
|
options: Options(
|
||||||
|
contentType: Headers.formUrlEncodedContentType,
|
||||||
|
// headers: {'user-agent': ApiConstants.userAgent}
|
||||||
|
),
|
||||||
|
);
|
||||||
|
print(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
// web端验证码
|
||||||
|
static Future sendWebSmsCode({
|
||||||
|
int? cid,
|
||||||
|
required int tel,
|
||||||
|
required String token,
|
||||||
|
required String challenge,
|
||||||
|
required String validate,
|
||||||
|
required String seccode,
|
||||||
|
}) async {
|
||||||
|
Map data = {
|
||||||
|
'cid': cid,
|
||||||
|
'tel': tel,
|
||||||
|
'token': token,
|
||||||
|
'challenge': challenge,
|
||||||
|
'validate': validate,
|
||||||
|
'seccode': seccode,
|
||||||
|
};
|
||||||
|
FormData formData = FormData.fromMap({...data});
|
||||||
|
var res = await Request().post(
|
||||||
|
Api.smsCode,
|
||||||
|
data: formData,
|
||||||
|
options: Options(
|
||||||
|
contentType: Headers.formUrlEncodedContentType,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
print(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
// web端验证码登录
|
||||||
|
static Future loginInByWebSmsCode() async {}
|
||||||
|
|
||||||
|
// web端密码登录
|
||||||
|
static Future liginInByWebPwd() async {}
|
||||||
|
|
||||||
|
// app端验证码
|
||||||
|
static Future sendAppSmsCode({
|
||||||
|
int? cid,
|
||||||
|
required int tel,
|
||||||
|
required String token,
|
||||||
|
required String challenge,
|
||||||
|
required String validate,
|
||||||
|
required String seccode,
|
||||||
|
}) async {
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
'cid': cid,
|
||||||
|
'tel': tel,
|
||||||
|
'login_session_id': const Uuid().v4().replaceAll('-', ''),
|
||||||
|
'recaptcha_token': token,
|
||||||
|
'gee_challenge': challenge,
|
||||||
|
'gee_validate': validate,
|
||||||
|
'gee_seccode': seccode,
|
||||||
|
'channel': 'bili',
|
||||||
|
'buvid': buvid(),
|
||||||
|
'local_id': buvid(),
|
||||||
|
// 'ts': DateTime.now().millisecondsSinceEpoch ~/ 1000,
|
||||||
|
'statistics': {
|
||||||
|
"appId": 1,
|
||||||
|
"platform": 3,
|
||||||
|
"version": "7.52.0",
|
||||||
|
"abtest": ""
|
||||||
|
},
|
||||||
|
};
|
||||||
|
// FormData formData = FormData.fromMap({...data});
|
||||||
|
var res = await Request().post(
|
||||||
|
Api.appSmsCode,
|
||||||
|
data: data,
|
||||||
|
options: Options(
|
||||||
|
contentType: Headers.formUrlEncodedContentType,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
print(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String buvid() {
|
||||||
|
var mac = <String>[];
|
||||||
|
var random = Random();
|
||||||
|
|
||||||
|
for (var i = 0; i < 6; i++) {
|
||||||
|
var min = 0;
|
||||||
|
var max = 0xff;
|
||||||
|
var num = (random.nextInt(max - min + 1) + min).toRadixString(16);
|
||||||
|
mac.add(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
var md5Str = md5.convert(utf8.encode(mac.join(':'))).toString();
|
||||||
|
var md5Arr = md5Str.split('');
|
||||||
|
return 'XY${md5Arr[2]}${md5Arr[12]}${md5Arr[22]}$md5Str';
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取盐hash跟PubKey
|
||||||
|
static Future getWebKey() async {
|
||||||
|
var res = await Request().get(Api.getWebKey,
|
||||||
|
data: {'disable_rcmd': 0, 'local_id': LoginUtils.generateBuvid()});
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {'status': true, 'data': res.data['data']};
|
||||||
|
} else {
|
||||||
|
return {'status': false, 'data': {}, 'msg': res.data['message']};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// app端密码登录
|
||||||
|
static Future loginInByMobPwd({
|
||||||
|
required String tel,
|
||||||
|
required String password,
|
||||||
|
required String key,
|
||||||
|
required String rhash,
|
||||||
|
}) async {
|
||||||
|
dynamic publicKey = RSAKeyParser().parse(key);
|
||||||
|
String passwordEncryptyed =
|
||||||
|
Encrypter(RSA(publicKey: publicKey)).encrypt(rhash + password).base64;
|
||||||
|
Map<String, dynamic> data = {
|
||||||
|
'username': tel,
|
||||||
|
'password': passwordEncryptyed,
|
||||||
|
'local_id': LoginUtils.generateBuvid(),
|
||||||
|
'disable_rcmd': "0",
|
||||||
|
};
|
||||||
|
var res = await Request().post(
|
||||||
|
Api.loginInByPwdApi,
|
||||||
|
data: data,
|
||||||
|
options: Options(
|
||||||
|
contentType: Headers.formUrlEncodedContentType,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
print(res);
|
||||||
|
}
|
||||||
|
}
|
49
lib/models/login/index.dart
Normal file
49
lib/models/login/index.dart
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
class CaptchaDataModel {
|
||||||
|
CaptchaDataModel({
|
||||||
|
this.type,
|
||||||
|
this.token,
|
||||||
|
this.geetest,
|
||||||
|
this.tencent,
|
||||||
|
this.validate,
|
||||||
|
this.seccode,
|
||||||
|
});
|
||||||
|
|
||||||
|
String? type;
|
||||||
|
String? token;
|
||||||
|
GeetestData? geetest;
|
||||||
|
Tencent? tencent;
|
||||||
|
String? validate;
|
||||||
|
String? seccode;
|
||||||
|
|
||||||
|
CaptchaDataModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
type = json["type"];
|
||||||
|
token = json["token"];
|
||||||
|
geetest =
|
||||||
|
json["geetest"] != null ? GeetestData.fromJson(json["geetest"]) : null;
|
||||||
|
tencent =
|
||||||
|
json["tencent"] != null ? Tencent.fromJson(json["tencent"]) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GeetestData {
|
||||||
|
GeetestData({
|
||||||
|
this.challenge,
|
||||||
|
this.gt,
|
||||||
|
});
|
||||||
|
|
||||||
|
String? challenge;
|
||||||
|
String? gt;
|
||||||
|
|
||||||
|
GeetestData.fromJson(Map<String, dynamic> json) {
|
||||||
|
challenge = json["challenge"];
|
||||||
|
gt = json["gt"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Tencent {
|
||||||
|
Tencent({this.appid});
|
||||||
|
String? appid;
|
||||||
|
Tencent.fromJson(Map<String, dynamic> json) {
|
||||||
|
appid = json["appid"];
|
||||||
|
}
|
||||||
|
}
|
204
lib/pages/login/controller.dart
Normal file
204
lib/pages/login/controller.dart
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pilipala/http/login.dart';
|
||||||
|
import 'package:gt3_flutter_plugin/gt3_flutter_plugin.dart';
|
||||||
|
import 'package:pilipala/models/login/index.dart';
|
||||||
|
|
||||||
|
class LoginPageController extends GetxController {
|
||||||
|
final GlobalKey mobFormKey = GlobalKey<FormState>();
|
||||||
|
final GlobalKey passwordFormKey = GlobalKey<FormState>();
|
||||||
|
final GlobalKey msgCodeFormKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
|
final TextEditingController mobTextController = TextEditingController();
|
||||||
|
final TextEditingController passwordTextController = TextEditingController();
|
||||||
|
final TextEditingController msgCodeTextController = TextEditingController();
|
||||||
|
|
||||||
|
final FocusNode mobTextFieldNode = FocusNode();
|
||||||
|
final FocusNode passwordTextFieldNode = FocusNode();
|
||||||
|
final FocusNode msgCodeTextFieldNode = FocusNode();
|
||||||
|
|
||||||
|
final PageController pageViewController = PageController();
|
||||||
|
|
||||||
|
RxInt currentIndex = 0.obs;
|
||||||
|
|
||||||
|
final Gt3FlutterPlugin captcha = Gt3FlutterPlugin();
|
||||||
|
|
||||||
|
// 默认密码登录
|
||||||
|
RxInt loginType = 0.obs;
|
||||||
|
|
||||||
|
// 监听pageView切换
|
||||||
|
void onPageChange(int index) {
|
||||||
|
currentIndex.value = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 输入手机号 下一页
|
||||||
|
void nextStep() async {
|
||||||
|
if ((mobFormKey.currentState as FormState).validate()) {
|
||||||
|
await pageViewController.animateToPage(
|
||||||
|
1,
|
||||||
|
duration: const Duration(microseconds: 3000),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
);
|
||||||
|
passwordTextFieldNode.requestFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上一页
|
||||||
|
void previousPage() async {
|
||||||
|
passwordTextFieldNode.unfocus();
|
||||||
|
await Future.delayed(const Duration(milliseconds: 200));
|
||||||
|
pageViewController.animateToPage(
|
||||||
|
0,
|
||||||
|
duration: const Duration(microseconds: 300),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换登录方式
|
||||||
|
void changeLoginType() {
|
||||||
|
loginType.value = loginType.value == 0 ? 1 : 0;
|
||||||
|
if (loginType.value == 0) {
|
||||||
|
passwordTextFieldNode.requestFocus();
|
||||||
|
} else {
|
||||||
|
msgCodeTextFieldNode.requestFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// app端密码登录
|
||||||
|
void loginInByAppPassword() async {
|
||||||
|
if ((passwordFormKey.currentState as FormState).validate()) {
|
||||||
|
var webKeyRes = await LoginHttp.getWebKey();
|
||||||
|
if (webKeyRes['status']) {
|
||||||
|
String rhash = webKeyRes['data']['hash'];
|
||||||
|
String key = webKeyRes['data']['key'];
|
||||||
|
LoginHttp.loginInByMobPwd(
|
||||||
|
tel: mobTextController.text,
|
||||||
|
password: passwordTextController.text,
|
||||||
|
key: key,
|
||||||
|
rhash: rhash,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
SmartDialog.showToast(webKeyRes['msg']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证码登录
|
||||||
|
void loginInByCode() {
|
||||||
|
if ((msgCodeFormKey.currentState as FormState).validate()) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// app端验证码
|
||||||
|
void getMsgCode() async {
|
||||||
|
getCaptcha((data) async {
|
||||||
|
CaptchaDataModel captchaData = data;
|
||||||
|
var res = await LoginHttp.sendAppSmsCode(
|
||||||
|
cid: 86,
|
||||||
|
tel: 13734077064,
|
||||||
|
token: captchaData.token!,
|
||||||
|
challenge: captchaData.geetest!.challenge!,
|
||||||
|
validate: captchaData.validate!,
|
||||||
|
seccode: captchaData.seccode!,
|
||||||
|
);
|
||||||
|
print(res);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 申请极验验证码
|
||||||
|
Future getCaptcha(oncall) async {
|
||||||
|
SmartDialog.showLoading(msg: '请求中...');
|
||||||
|
var result = await LoginHttp.queryCaptcha();
|
||||||
|
if (result['status']) {
|
||||||
|
CaptchaDataModel captchaData = result['data'];
|
||||||
|
var registerData = Gt3RegisterData(
|
||||||
|
challenge: captchaData.geetest!.challenge,
|
||||||
|
gt: captchaData.geetest!.gt!,
|
||||||
|
success: true,
|
||||||
|
);
|
||||||
|
captcha.addEventHandler(onShow: (Map<String, dynamic> message) async {
|
||||||
|
SmartDialog.dismiss();
|
||||||
|
}, onClose: (Map<String, dynamic> message) async {
|
||||||
|
SmartDialog.showToast('关闭验证');
|
||||||
|
}, onResult: (Map<String, dynamic> message) async {
|
||||||
|
debugPrint("Captcha result: $message");
|
||||||
|
String code = message["code"];
|
||||||
|
if (code == "1") {
|
||||||
|
// 发送 message["result"] 中的数据向 B 端的业务服务接口进行查询
|
||||||
|
SmartDialog.showToast('验证成功');
|
||||||
|
captchaData.validate = message['result']['geetest_validate'];
|
||||||
|
captchaData.seccode = message['result']['geetest_seccode'];
|
||||||
|
captchaData.geetest!.challenge =
|
||||||
|
message['result']['geetest_challenge'];
|
||||||
|
oncall(captchaData);
|
||||||
|
} else {
|
||||||
|
// 终端用户完成验证失败,自动重试 If the verification fails, it will be automatically retried.
|
||||||
|
debugPrint("Captcha result code : $code");
|
||||||
|
}
|
||||||
|
}, onError: (Map<String, dynamic> message) async {
|
||||||
|
String code = message["code"];
|
||||||
|
|
||||||
|
// 处理验证中返回的错误 Handling errors returned in verification
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
// Android 平台
|
||||||
|
if (code == "-2") {
|
||||||
|
// Dart 调用异常 Call exception
|
||||||
|
} else if (code == "-1") {
|
||||||
|
// Gt3RegisterData 参数不合法 Parameter is invalid
|
||||||
|
} else if (code == "201") {
|
||||||
|
// 网络无法访问 Network inaccessible
|
||||||
|
} else if (code == "202") {
|
||||||
|
// Json 解析错误 Analysis error
|
||||||
|
} else if (code == "204") {
|
||||||
|
// WebView 加载超时,请检查是否混淆极验 SDK Load timed out
|
||||||
|
} else if (code == "204_1") {
|
||||||
|
// WebView 加载前端页面错误,请查看日志 Error loading front-end page, please check the log
|
||||||
|
} else if (code == "204_2") {
|
||||||
|
// WebView 加载 SSLError
|
||||||
|
} else if (code == "206") {
|
||||||
|
// gettype 接口错误或返回为 null API error or return null
|
||||||
|
} else if (code == "207") {
|
||||||
|
// getphp 接口错误或返回为 null API error or return null
|
||||||
|
} else if (code == "208") {
|
||||||
|
// ajax 接口错误或返回为 null API error or return null
|
||||||
|
} else {
|
||||||
|
// 更多错误码参考开发文档 More error codes refer to the development document
|
||||||
|
// https://docs.geetest.com/sensebot/apirefer/errorcode/android
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Platform.isIOS) {
|
||||||
|
// iOS 平台
|
||||||
|
if (code == "-1009") {
|
||||||
|
// 网络无法访问 Network inaccessible
|
||||||
|
} else if (code == "-1004") {
|
||||||
|
// 无法查找到 HOST Unable to find HOST
|
||||||
|
} else if (code == "-1002") {
|
||||||
|
// 非法的 URL Illegal URL
|
||||||
|
} else if (code == "-1001") {
|
||||||
|
// 网络超时 Network timeout
|
||||||
|
} else if (code == "-999") {
|
||||||
|
// 请求被意外中断, 一般由用户进行取消操作导致 The interrupted request was usually caused by the user cancelling the operation
|
||||||
|
} else if (code == "-21") {
|
||||||
|
// 使用了重复的 challenge Duplicate challenges are used
|
||||||
|
// 检查获取 challenge 是否进行了缓存 Check if the fetch challenge is cached
|
||||||
|
} else if (code == "-20") {
|
||||||
|
// 尝试过多, 重新引导用户触发验证即可 Try too many times, lead the user to request verification again
|
||||||
|
} else if (code == "-10") {
|
||||||
|
// 预判断时被封禁, 不会再进行图形验证 Banned during pre-judgment, and no more image captcha verification
|
||||||
|
} else if (code == "-2") {
|
||||||
|
// Dart 调用异常 Call exception
|
||||||
|
} else if (code == "-1") {
|
||||||
|
// Gt3RegisterData 参数不合法 Parameter is invalid
|
||||||
|
} else {
|
||||||
|
// 更多错误码参考开发文档 More error codes refer to the development document
|
||||||
|
// https://docs.geetest.com/sensebot/apirefer/errorcode/ios
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
captcha.startCaptcha(registerData);
|
||||||
|
} else {}
|
||||||
|
}
|
||||||
|
}
|
4
lib/pages/login/index.dart
Normal file
4
lib/pages/login/index.dart
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
library login;
|
||||||
|
|
||||||
|
export './controller.dart';
|
||||||
|
export 'view.dart';
|
362
lib/pages/login/view.dart
Normal file
362
lib/pages/login/view.dart
Normal file
@ -0,0 +1,362 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
import 'controller.dart';
|
||||||
|
|
||||||
|
class LoginPage extends StatefulWidget {
|
||||||
|
const LoginPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<LoginPage> createState() => _LoginPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LoginPageState extends State<LoginPage> {
|
||||||
|
final LoginPageController _loginPageCtr = Get.put(LoginPageController());
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
leading: Obx(
|
||||||
|
() => _loginPageCtr.currentIndex.value == 0
|
||||||
|
? IconButton(
|
||||||
|
onPressed: () async {
|
||||||
|
_loginPageCtr.mobTextFieldNode.unfocus();
|
||||||
|
await Future.delayed(const Duration(milliseconds: 200));
|
||||||
|
Get.back();
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.close_outlined),
|
||||||
|
)
|
||||||
|
: IconButton(
|
||||||
|
onPressed: () => _loginPageCtr.previousPage(),
|
||||||
|
icon: const Icon(Icons.arrow_back),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: PageView(
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
controller: _loginPageCtr.pageViewController,
|
||||||
|
onPageChanged: (int index) => _loginPageCtr.onPageChange(index),
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
left: 20,
|
||||||
|
right: 20,
|
||||||
|
top: 10,
|
||||||
|
bottom: MediaQuery.of(context).padding.bottom + 10,
|
||||||
|
),
|
||||||
|
child: Form(
|
||||||
|
key: _loginPageCtr.mobFormKey,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'登录',
|
||||||
|
style: Theme.of(context).textTheme.titleLarge!.copyWith(
|
||||||
|
letterSpacing: 1,
|
||||||
|
height: 2.1,
|
||||||
|
fontSize: 34,
|
||||||
|
fontWeight: FontWeight.w500),
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'请使用您的 BiliBili 账号登录。',
|
||||||
|
style: Theme.of(context).textTheme.titleSmall!,
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {},
|
||||||
|
child: const Icon(Icons.info_outline, size: 16),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.only(top: 38, bottom: 15),
|
||||||
|
child: TextFormField(
|
||||||
|
controller: _loginPageCtr.mobTextController,
|
||||||
|
focusNode: _loginPageCtr.mobTextFieldNode,
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
isDense: true,
|
||||||
|
labelText: '输入手机号码',
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(6.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// 校验用户名
|
||||||
|
validator: (v) {
|
||||||
|
return v!.trim().isNotEmpty ? null : "手机号码不能为空";
|
||||||
|
},
|
||||||
|
onSaved: (val) {
|
||||||
|
print(val);
|
||||||
|
},
|
||||||
|
onEditingComplete: () {
|
||||||
|
_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(),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
TextButton(onPressed: () {}, child: const Text('中国大陆')),
|
||||||
|
TextButton(
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
|
||||||
|
foregroundColor:
|
||||||
|
Theme.of(context).colorScheme.onPrimary,
|
||||||
|
backgroundColor:
|
||||||
|
Theme.of(context).colorScheme.primary, // 设置按钮背景色
|
||||||
|
),
|
||||||
|
onPressed: () => _loginPageCtr.nextStep(),
|
||||||
|
child: const Text('下一步'),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
left: 20,
|
||||||
|
right: 20,
|
||||||
|
top: 10,
|
||||||
|
bottom: MediaQuery.of(context).padding.bottom + 10,
|
||||||
|
),
|
||||||
|
child: Obx(
|
||||||
|
() => _loginPageCtr.loginType.value == 0
|
||||||
|
? Form(
|
||||||
|
key: _loginPageCtr.passwordFormKey,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'密码登录',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.titleLarge!
|
||||||
|
.copyWith(
|
||||||
|
letterSpacing: 1,
|
||||||
|
height: 2.1,
|
||||||
|
fontSize: 34,
|
||||||
|
fontWeight: FontWeight.w500),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
IconButton(
|
||||||
|
style: ButtonStyle(
|
||||||
|
backgroundColor:
|
||||||
|
MaterialStateProperty.resolveWith(
|
||||||
|
(states) {
|
||||||
|
return Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.primary
|
||||||
|
.withOpacity(0.1);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
onPressed: () =>
|
||||||
|
_loginPageCtr.changeLoginType(),
|
||||||
|
icon: const Icon(Icons.swap_vert_outlined),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'请输入您的 BiliBili 密码。',
|
||||||
|
style: Theme.of(context).textTheme.titleSmall!,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.only(top: 38, bottom: 15),
|
||||||
|
child: TextFormField(
|
||||||
|
controller: _loginPageCtr.passwordTextController,
|
||||||
|
focusNode: _loginPageCtr.passwordTextFieldNode,
|
||||||
|
keyboardType: TextInputType.visiblePassword,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
isDense: true,
|
||||||
|
labelText: '输入密码',
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(6.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// 校验用户名
|
||||||
|
validator: (v) {
|
||||||
|
return v!.trim().isNotEmpty ? null : "密码不能为空";
|
||||||
|
},
|
||||||
|
onSaved: (val) {
|
||||||
|
print(val);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => _loginPageCtr.previousPage(),
|
||||||
|
child: const Text('上一步'),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 15),
|
||||||
|
TextButton(
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.fromLTRB(20, 0, 20, 0),
|
||||||
|
foregroundColor:
|
||||||
|
Theme.of(context).colorScheme.onPrimary,
|
||||||
|
backgroundColor: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.primary, // 设置按钮背景色
|
||||||
|
),
|
||||||
|
onPressed: () =>
|
||||||
|
_loginPageCtr.loginInByAppPassword(),
|
||||||
|
child: const Text('确认登录'),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Form(
|
||||||
|
key: _loginPageCtr.msgCodeFormKey,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'验证码登录',
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.titleLarge!
|
||||||
|
.copyWith(
|
||||||
|
letterSpacing: 1,
|
||||||
|
height: 2.1,
|
||||||
|
fontSize: 34,
|
||||||
|
fontWeight: FontWeight.w500),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
IconButton(
|
||||||
|
style: ButtonStyle(
|
||||||
|
backgroundColor:
|
||||||
|
MaterialStateProperty.resolveWith(
|
||||||
|
(states) {
|
||||||
|
return Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.primary
|
||||||
|
.withOpacity(0.1);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
onPressed: () =>
|
||||||
|
_loginPageCtr.changeLoginType(),
|
||||||
|
icon: const Icon(Icons.swap_vert_outlined),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'请输入收到到验证码。',
|
||||||
|
style: Theme.of(context).textTheme.titleSmall!,
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
margin: const EdgeInsets.only(top: 38, bottom: 15),
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
TextFormField(
|
||||||
|
controller:
|
||||||
|
_loginPageCtr.msgCodeTextController,
|
||||||
|
focusNode: _loginPageCtr.msgCodeTextFieldNode,
|
||||||
|
maxLength: 6,
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
isDense: true,
|
||||||
|
labelText: '输入验证码',
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(6.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
// 校验用户名
|
||||||
|
validator: (v) {
|
||||||
|
return v!.trim().isNotEmpty
|
||||||
|
? null
|
||||||
|
: "验证码不能为空";
|
||||||
|
},
|
||||||
|
onSaved: (val) {
|
||||||
|
print(val);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
right: 8,
|
||||||
|
top: 4,
|
||||||
|
child: Center(
|
||||||
|
child: TextButton(
|
||||||
|
onPressed: () =>
|
||||||
|
_loginPageCtr.getMsgCode(),
|
||||||
|
child: const Text('获取验证码'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => _loginPageCtr.previousPage(),
|
||||||
|
child: const Text('上一步'),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 15),
|
||||||
|
TextButton(
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.fromLTRB(20, 0, 20, 0),
|
||||||
|
foregroundColor:
|
||||||
|
Theme.of(context).colorScheme.onPrimary,
|
||||||
|
backgroundColor: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.primary, // 设置按钮背景色
|
||||||
|
),
|
||||||
|
onPressed: () => _loginPageCtr.loginInByCode(),
|
||||||
|
child: const Text('确认登录'),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -41,6 +41,7 @@ class MineController extends GetxController {
|
|||||||
'pageTitle': '登录bilibili',
|
'pageTitle': '登录bilibili',
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
// 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!;
|
||||||
|
@ -117,6 +117,13 @@ class SSearchController extends GetxController {
|
|||||||
submit();
|
submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onLongSelect(word) {
|
||||||
|
int index = historyList.indexOf(word);
|
||||||
|
historyList.value = historyList.removeAt(index);
|
||||||
|
historyList.refresh();
|
||||||
|
histiryWord.put('cacheList', historyList);
|
||||||
|
}
|
||||||
|
|
||||||
onClearHis() {
|
onClearHis() {
|
||||||
historyList.value = [];
|
historyList.value = [];
|
||||||
historyCacheList = [];
|
historyCacheList = [];
|
||||||
|
@ -299,20 +299,24 @@ class _SearchPageState extends State<SearchPage> with RouteAware {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
// if (_searchController.historyList.isNotEmpty)
|
// if (_searchController.historyList.isNotEmpty)
|
||||||
Wrap(
|
Obx(() => Wrap(
|
||||||
spacing: 8,
|
spacing: 8,
|
||||||
runSpacing: 8,
|
runSpacing: 8,
|
||||||
direction: Axis.horizontal,
|
direction: Axis.horizontal,
|
||||||
textDirection: TextDirection.ltr,
|
textDirection: TextDirection.ltr,
|
||||||
children: [
|
children: [
|
||||||
for (int i = 0; i < _searchController.historyList.length; i++)
|
for (int i = 0;
|
||||||
SearchText(
|
i < _searchController.historyList.length;
|
||||||
searchText: _searchController.historyList[i],
|
i++)
|
||||||
searchTextIdx: i,
|
SearchText(
|
||||||
onSelect: (value) => _searchController.onSelect(value),
|
searchText: _searchController.historyList[i],
|
||||||
)
|
searchTextIdx: i,
|
||||||
],
|
onSelect: (value) => _searchController.onSelect(value),
|
||||||
),
|
onLongSelect: (value) =>
|
||||||
|
_searchController.onLongSelect(value),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -4,8 +4,14 @@ class SearchText extends StatelessWidget {
|
|||||||
final String? searchText;
|
final String? searchText;
|
||||||
final Function? onSelect;
|
final Function? onSelect;
|
||||||
final int? searchTextIdx;
|
final int? searchTextIdx;
|
||||||
const SearchText(
|
final Function? onLongSelect;
|
||||||
{super.key, this.searchText, this.onSelect, this.searchTextIdx});
|
const SearchText({
|
||||||
|
super.key,
|
||||||
|
this.searchText,
|
||||||
|
this.onSelect,
|
||||||
|
this.searchTextIdx,
|
||||||
|
this.onLongSelect,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -18,6 +24,9 @@ class SearchText extends StatelessWidget {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
onSelect!(searchText);
|
onSelect!(searchText);
|
||||||
},
|
},
|
||||||
|
onLongPress: () {
|
||||||
|
onLongSelect!(searchText);
|
||||||
|
},
|
||||||
borderRadius: BorderRadius.circular(6),
|
borderRadius: BorderRadius.circular(6),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding:
|
padding:
|
||||||
|
@ -19,6 +19,7 @@ import 'package:pilipala/pages/hot/index.dart';
|
|||||||
import 'package:pilipala/pages/html/index.dart';
|
import 'package:pilipala/pages/html/index.dart';
|
||||||
import 'package:pilipala/pages/later/index.dart';
|
import 'package:pilipala/pages/later/index.dart';
|
||||||
import 'package:pilipala/pages/liveRoom/view.dart';
|
import 'package:pilipala/pages/liveRoom/view.dart';
|
||||||
|
import 'package:pilipala/pages/login/index.dart';
|
||||||
import 'package:pilipala/pages/member/index.dart';
|
import 'package:pilipala/pages/member/index.dart';
|
||||||
import 'package:pilipala/pages/member_search/index.dart';
|
import 'package:pilipala/pages/member_search/index.dart';
|
||||||
import 'package:pilipala/pages/preview/index.dart';
|
import 'package:pilipala/pages/preview/index.dart';
|
||||||
@ -122,6 +123,8 @@ class Routes {
|
|||||||
CustomGetPage(name: '/playSpeedSet', page: () => const PlaySpeedPage()),
|
CustomGetPage(name: '/playSpeedSet', page: () => const PlaySpeedPage()),
|
||||||
// 收藏搜索
|
// 收藏搜索
|
||||||
CustomGetPage(name: '/favSearch', page: () => const FavSearchPage()),
|
CustomGetPage(name: '/favSearch', page: () => const FavSearchPage()),
|
||||||
|
// 登录页面
|
||||||
|
CustomGetPage(name: '/loginPage', page: () => const LoginPage()),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:crypto/crypto.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/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:uuid/uuid.dart';
|
||||||
|
|
||||||
class LoginUtils {
|
class LoginUtils {
|
||||||
static Future refreshLoginStatus(bool status) async {
|
static Future refreshLoginStatus(bool status) async {
|
||||||
@ -27,4 +32,29 @@ class LoginUtils {
|
|||||||
SmartDialog.showToast('refreshLoginStatus error: ${err.toString()}');
|
SmartDialog.showToast('refreshLoginStatus error: ${err.toString()}');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String buvid() {
|
||||||
|
var mac = <String>[];
|
||||||
|
var random = Random();
|
||||||
|
|
||||||
|
for (var i = 0; i < 6; i++) {
|
||||||
|
var min = 0;
|
||||||
|
var max = 0xff;
|
||||||
|
var num = (random.nextInt(max - min + 1) + min).toRadixString(16);
|
||||||
|
mac.add(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
var md5Str = md5.convert(utf8.encode(mac.join(':'))).toString();
|
||||||
|
var md5Arr = md5Str.split('');
|
||||||
|
return 'XY${md5Arr[2]}${md5Arr[12]}${md5Arr[22]}$md5Str';
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getUUID() {
|
||||||
|
return const Uuid().v4().replaceAll('-', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
static String generateBuvid() {
|
||||||
|
String uuid = getUUID() + getUUID();
|
||||||
|
return 'XY${uuid.substring(0, 35).toUpperCase()}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
26
pubspec.lock
26
pubspec.lock
@ -49,6 +49,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.2"
|
version: "2.4.2"
|
||||||
|
asn1lib:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: asn1lib
|
||||||
|
sha256: "21afe4333076c02877d14f4a89df111e658a6d466cbfc802eb705eb91bd5adfd"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.5.0"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -401,6 +409,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.3"
|
version: "2.0.3"
|
||||||
|
encrypt:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: encrypt
|
||||||
|
sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.0.3"
|
||||||
extended_image:
|
extended_image:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -613,6 +629,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.1"
|
version: "2.3.1"
|
||||||
|
gt3_flutter_plugin:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: gt3_flutter_plugin
|
||||||
|
sha256: f12bff2bfbcf27467833f8d564dcc24ee2f1b3254a7c7cf5eb2c4590baf11cc1
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.8"
|
||||||
hive:
|
hive:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -1420,7 +1444,7 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.7"
|
version: "3.0.7"
|
||||||
uuid:
|
uuid:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: uuid
|
name: uuid
|
||||||
sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313"
|
sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313"
|
||||||
|
@ -82,6 +82,7 @@ dependencies:
|
|||||||
custom_sliding_segmented_control: ^1.7.5
|
custom_sliding_segmented_control: ^1.7.5
|
||||||
# 加密
|
# 加密
|
||||||
crypto: ^3.0.3
|
crypto: ^3.0.3
|
||||||
|
encrypt: ^5.0.3
|
||||||
|
|
||||||
# 视频播放器
|
# 视频播放器
|
||||||
media_kit: ^1.1.10 # Primary package.
|
media_kit: ^1.1.10 # Primary package.
|
||||||
@ -128,6 +129,9 @@ dependencies:
|
|||||||
html: ^0.15.4
|
html: ^0.15.4
|
||||||
# html渲染
|
# html渲染
|
||||||
flutter_html: ^3.0.0-beta.2
|
flutter_html: ^3.0.0-beta.2
|
||||||
|
# 极验
|
||||||
|
gt3_flutter_plugin: ^0.0.8
|
||||||
|
uuid: ^3.0.7
|
||||||
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
|
Reference in New Issue
Block a user