mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-08-05 18:20:10 +08:00
feat: load config from text (#1772)
* feat: load config from text * opt: login utils * update Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me> --------- Co-authored-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
committed by
GitHub
parent
b4daf5fbd8
commit
244ef22f54
@@ -367,15 +367,15 @@ class FavHttp {
|
||||
}
|
||||
|
||||
static Future<LoadingState<FavPgcData>> favPgc({
|
||||
required dynamic mid,
|
||||
required int type,
|
||||
required int pn,
|
||||
int? followStatus,
|
||||
Object? mid,
|
||||
}) async {
|
||||
var res = await Request().get(
|
||||
Api.favPgc,
|
||||
queryParameters: {
|
||||
'vmid': mid,
|
||||
'vmid': mid ?? Accounts.main.mid,
|
||||
'type': type,
|
||||
'follow_status': ?followStatus,
|
||||
'pn': pn,
|
||||
|
||||
@@ -61,14 +61,20 @@ class Request {
|
||||
// final html = await Request().get(Api.dynamicSpmPrefix,
|
||||
// options: Options(extra: {'account': account}));
|
||||
// final String spmPrefix = _spmPrefixExp.firstMatch(html.data)!.group(1)!;
|
||||
final String randPngEnd = base64.encode(
|
||||
List<int>.generate(32, (_) => Utils.random.nextInt(256)) +
|
||||
List<int>.filled(4, 0) +
|
||||
[73, 69, 78, 68] +
|
||||
List<int>.generate(4, (_) => Utils.random.nextInt(256)),
|
||||
);
|
||||
final String randPngEnd = base64.encode([
|
||||
...Iterable<int>.generate(32, (_) => Utils.random.nextInt(256)),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
73,
|
||||
69,
|
||||
78,
|
||||
68,
|
||||
...Iterable<int>.generate(4, (_) => Utils.random.nextInt(256)),
|
||||
]);
|
||||
|
||||
String jsonData = json.encode({
|
||||
final jsonData = json.encode({
|
||||
'3064': 1,
|
||||
'39c8': '333.1387.fp.risk',
|
||||
'3c43': {
|
||||
|
||||
@@ -4,22 +4,22 @@ part 'stat.g.dart';
|
||||
|
||||
@HiveType(typeId: 1)
|
||||
class UserStat {
|
||||
UserStat({
|
||||
const UserStat({
|
||||
this.following,
|
||||
this.follower,
|
||||
this.dynamicCount,
|
||||
});
|
||||
|
||||
@HiveField(0)
|
||||
int? following;
|
||||
final int? following;
|
||||
@HiveField(1)
|
||||
int? follower;
|
||||
final int? follower;
|
||||
@HiveField(2)
|
||||
int? dynamicCount;
|
||||
final int? dynamicCount;
|
||||
|
||||
UserStat.fromJson(Map<String, dynamic> json) {
|
||||
following = json['following'];
|
||||
follower = json['follower'];
|
||||
dynamicCount = json['dynamic_count'];
|
||||
}
|
||||
factory UserStat.fromJson(Map<String, dynamic> json) => UserStat(
|
||||
following: json['following'],
|
||||
follower: json['follower'],
|
||||
dynamicCount: json['dynamic_count'],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -434,6 +434,78 @@ Future<void> showImportExportDialog<T>(
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
dense: true,
|
||||
title: Text('输入$title', style: style),
|
||||
onTap: () {
|
||||
Get.back();
|
||||
final key = GlobalKey<FormFieldState<String>>();
|
||||
late T json;
|
||||
String? forceErrorText;
|
||||
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text('输入$title'),
|
||||
constraints: const BoxConstraints(
|
||||
minWidth: 420,
|
||||
maxWidth: 420,
|
||||
),
|
||||
content: TextFormField(
|
||||
key: key,
|
||||
minLines: 4,
|
||||
maxLines: 12,
|
||||
autofocus: true,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
errorMaxLines: 3,
|
||||
),
|
||||
validator: (value) {
|
||||
if (forceErrorText != null) return forceErrorText;
|
||||
try {
|
||||
json = jsonDecode(value!) as T;
|
||||
return null;
|
||||
} catch (e) {
|
||||
if (e is FormatException) {}
|
||||
return '解析json失败:$e';
|
||||
}
|
||||
},
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: Get.back,
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
if (key.currentState?.validate() == true) {
|
||||
try {
|
||||
if (await fromJson(json)) {
|
||||
Get.back();
|
||||
SmartDialog.showToast('导入成功');
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
forceErrorText = '导入失败:$e';
|
||||
}
|
||||
key.currentState?.validate();
|
||||
forceErrorText = null;
|
||||
}
|
||||
},
|
||||
child: const Text('确定'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
|
||||
@@ -9,6 +9,7 @@ import 'package:PiliPlus/models_new/follow/data.dart';
|
||||
import 'package:PiliPlus/pages/common/common_controller.dart';
|
||||
import 'package:PiliPlus/pages/dynamics_tab/controller.dart';
|
||||
import 'package:PiliPlus/services/account_service.dart';
|
||||
import 'package:PiliPlus/utils/accounts.dart';
|
||||
import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:PiliPlus/utils/storage_pref.dart';
|
||||
import 'package:easy_debounce/easy_throttle.dart';
|
||||
@@ -16,7 +17,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class DynamicsController extends GetxController
|
||||
with GetSingleTickerProviderStateMixin, ScrollOrRefreshMixin {
|
||||
with GetSingleTickerProviderStateMixin, ScrollOrRefreshMixin, AccountMixin {
|
||||
@override
|
||||
final ScrollController scrollController = ScrollController();
|
||||
late final TabController tabController = TabController(
|
||||
@@ -40,7 +41,8 @@ class DynamicsController extends GetxController
|
||||
|
||||
final upPanelPosition = Pref.upPanelPosition;
|
||||
|
||||
AccountService accountService = Get.find<AccountService>();
|
||||
@override
|
||||
final AccountService accountService = Get.find<AccountService>();
|
||||
|
||||
DynamicsTabController? get controller {
|
||||
try {
|
||||
@@ -95,7 +97,7 @@ class DynamicsController extends GetxController
|
||||
isQuerying = true;
|
||||
|
||||
final res = await FollowHttp.followings(
|
||||
vmid: accountService.mid,
|
||||
vmid: Accounts.main.mid,
|
||||
pn: _upPage,
|
||||
orderType: 'attention',
|
||||
ps: 50,
|
||||
@@ -136,7 +138,7 @@ class DynamicsController extends GetxController
|
||||
DynamicsHttp.followUp(),
|
||||
if (_showAllUp)
|
||||
FollowHttp.followings(
|
||||
vmid: accountService.mid,
|
||||
vmid: Accounts.main.mid,
|
||||
pn: _upPage,
|
||||
orderType: 'attention',
|
||||
ps: 50,
|
||||
@@ -188,13 +190,13 @@ class DynamicsController extends GetxController
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> onRefresh() async {
|
||||
Future<void> onRefresh() {
|
||||
if (_showAllUp) {
|
||||
_upPage = 1;
|
||||
_cacheUpList = null;
|
||||
}
|
||||
queryFollowUp();
|
||||
await controller?.onRefresh();
|
||||
return controller!.onRefresh();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -231,4 +233,7 @@ class DynamicsController extends GetxController
|
||||
scrollController.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
@override
|
||||
void onChangeAccount(bool isLogin) => onRefresh();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:PiliPlus/models/common/image_type.dart';
|
||||
import 'package:PiliPlus/models/dynamics/up.dart';
|
||||
import 'package:PiliPlus/pages/dynamics/controller.dart';
|
||||
import 'package:PiliPlus/pages/live_follow/view.dart';
|
||||
import 'package:PiliPlus/utils/accounts.dart';
|
||||
import 'package:PiliPlus/utils/feed_back.dart';
|
||||
import 'package:PiliPlus/utils/page_utils.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
@@ -112,7 +113,7 @@ class _UpPanelState extends State<UpPanel> {
|
||||
UpItem(
|
||||
uname: '我',
|
||||
face: accountService.face.value,
|
||||
mid: accountService.mid,
|
||||
mid: Accounts.main.mid,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -6,12 +6,14 @@ import 'package:PiliPlus/models/dynamics/result.dart';
|
||||
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||
import 'package:PiliPlus/pages/dynamics/controller.dart';
|
||||
import 'package:PiliPlus/pages/main/controller.dart';
|
||||
import 'package:PiliPlus/services/account_service.dart';
|
||||
import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class DynamicsTabController
|
||||
extends CommonListController<DynamicsDataModel, DynamicItemModel> {
|
||||
extends CommonListController<DynamicsDataModel, DynamicItemModel>
|
||||
with AccountMixin {
|
||||
DynamicsTabController({required this.dynamicsType});
|
||||
final DynamicsTabType dynamicsType;
|
||||
String offset = '';
|
||||
@@ -87,4 +89,7 @@ class DynamicsTabController
|
||||
loadingState.refresh();
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
@override
|
||||
void onChangeAccount(bool isLogin) => onRefresh();
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import 'package:PiliPlus/http/video.dart';
|
||||
import 'package:PiliPlus/models_new/fav/fav_pgc/data.dart';
|
||||
import 'package:PiliPlus/models_new/fav/fav_pgc/list.dart';
|
||||
import 'package:PiliPlus/pages/common/multi_select/multi_select_controller.dart';
|
||||
import 'package:PiliPlus/utils/accounts.dart';
|
||||
import 'package:flutter/foundation.dart' show kDebugMode;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
@@ -39,7 +38,6 @@ class FavPgcController
|
||||
|
||||
@override
|
||||
Future<LoadingState<FavPgcData>> customGetData() => FavHttp.favPgc(
|
||||
mid: Accounts.main.mid,
|
||||
type: type,
|
||||
followStatus: followStatus,
|
||||
pn: page,
|
||||
|
||||
@@ -7,9 +7,10 @@ import 'package:PiliPlus/models_new/live/live_feed_index/data.dart';
|
||||
import 'package:PiliPlus/models_new/live/live_second_list/data.dart';
|
||||
import 'package:PiliPlus/models_new/live/live_second_list/tag.dart';
|
||||
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||
import 'package:PiliPlus/services/account_service.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class LiveController extends CommonListController {
|
||||
class LiveController extends CommonListController with AccountMixin {
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
@@ -140,4 +141,7 @@ class LiveController extends CommonListController {
|
||||
isEnd = false;
|
||||
queryData();
|
||||
}
|
||||
|
||||
@override
|
||||
void onChangeAccount(bool isLogin) => onRefresh();
|
||||
}
|
||||
|
||||
@@ -19,22 +19,24 @@ import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/storage_key.dart';
|
||||
import 'package:PiliPlus/utils/storage_pref.dart';
|
||||
import 'package:PiliPlus/utils/update.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:easy_debounce/easy_throttle.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class MainController extends GetxController
|
||||
with GetSingleTickerProviderStateMixin {
|
||||
AccountService accountService = Get.find<AccountService>();
|
||||
with GetSingleTickerProviderStateMixin, AccountMixin {
|
||||
@override
|
||||
final AccountService accountService = Get.find<AccountService>();
|
||||
|
||||
List<NavigationBarType> navigationBars = <NavigationBarType>[];
|
||||
|
||||
StreamController<bool>? bottomBarStream;
|
||||
late bool hideTabBar = Pref.hideTabBar;
|
||||
late dynamic controller;
|
||||
RxInt selectedIndex = 0.obs;
|
||||
final RxInt selectedIndex = 0.obs;
|
||||
|
||||
RxInt dynCount = 0.obs;
|
||||
final RxInt dynCount = 0.obs;
|
||||
late DynamicBadgeMode dynamicBadgeMode;
|
||||
late bool checkDynamic = Pref.checkDynamic;
|
||||
late int dynamicPeriod = Pref.dynamicPeriod * 60 * 1000;
|
||||
@@ -165,7 +167,7 @@ class MainController extends GetxController
|
||||
|
||||
var res = await Future.wait([_msgUnread(), _msgFeedUnread()]);
|
||||
|
||||
int count = res.fold(0, (prev, e) => prev + e);
|
||||
final count = res.sum;
|
||||
|
||||
final countStr = count == 0
|
||||
? ''
|
||||
@@ -332,4 +334,13 @@ class MainController extends GetxController
|
||||
controller.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
@override
|
||||
void onChangeAccount(bool isLogin) {
|
||||
if (isLogin) {
|
||||
getUnreadDynamic();
|
||||
} else {
|
||||
setDynCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,9 +89,7 @@ class _EditProfilePageState extends State<EditProfilePage> {
|
||||
res.data['data'],
|
||||
);
|
||||
_loadingState = Success(data);
|
||||
accountService
|
||||
..name.value = data.name!
|
||||
..face.value = data.face!;
|
||||
accountService.face.value = data.face!;
|
||||
try {
|
||||
UserInfoData userInfo = Pref.userInfoCache!
|
||||
..uname = data.name
|
||||
@@ -388,7 +386,6 @@ class _EditProfilePageState extends State<EditProfilePage> {
|
||||
data
|
||||
..name = _textController.text
|
||||
..coins = data.coins! - 6;
|
||||
accountService.name.value = _textController.text;
|
||||
try {
|
||||
UserInfoData userInfo = Pref.userInfoCache!
|
||||
..uname = _textController.text;
|
||||
|
||||
@@ -19,16 +19,17 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
|
||||
class MineController
|
||||
extends CommonDataController<FavFolderData, FavFolderData> {
|
||||
class MineController extends CommonDataController<FavFolderData, FavFolderData>
|
||||
with AccountMixin {
|
||||
@override
|
||||
AccountService accountService = Get.find<AccountService>();
|
||||
|
||||
int? favFolderCount;
|
||||
|
||||
// 用户信息 头像、昵称、lv
|
||||
Rx<UserInfoData> userInfo = UserInfoData().obs;
|
||||
final Rx<UserInfoData> userInfo = UserInfoData().obs;
|
||||
// 用户状态 动态、关注、粉丝
|
||||
Rx<UserStat> userStat = UserStat().obs;
|
||||
final Rx<UserStat> userStat = const UserStat().obs;
|
||||
|
||||
Rx<ThemeType> themeType = Pref.themeType.obs;
|
||||
|
||||
@@ -107,8 +108,6 @@ class MineController
|
||||
GStorage.userInfo.put('userInfoCache', data);
|
||||
}
|
||||
accountService
|
||||
..mid = data.mid!
|
||||
..name.value = data.uname!
|
||||
..face.value = data.face!
|
||||
..isLogin.value = true;
|
||||
} else {
|
||||
@@ -145,7 +144,7 @@ class MineController
|
||||
return FavHttp.userfavFolder(
|
||||
pn: 1,
|
||||
ps: 20,
|
||||
mid: accountService.mid,
|
||||
mid: Accounts.main.mid,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -293,4 +292,15 @@ class MineController
|
||||
queryUserInfo();
|
||||
return super.onRefresh();
|
||||
}
|
||||
|
||||
@override
|
||||
void onChangeAccount(bool isLogin) {
|
||||
if (isLogin) {
|
||||
onRefresh();
|
||||
} else {
|
||||
userInfo.value = UserInfoData();
|
||||
userStat.value = const UserStat();
|
||||
loadingState.value = LoadingState.loading();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,14 +14,16 @@ import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class PgcController
|
||||
extends CommonListController<List<PgcIndexItem>?, PgcIndexItem> {
|
||||
extends CommonListController<List<PgcIndexItem>?, PgcIndexItem>
|
||||
with AccountMixin {
|
||||
PgcController({required this.tabType});
|
||||
final HomeTabType tabType;
|
||||
|
||||
late final showPgcTimeline =
|
||||
tabType == HomeTabType.bangumi && Pref.showPgcTimeline;
|
||||
|
||||
AccountService accountService = Get.find<AccountService>();
|
||||
@override
|
||||
final accountService = Get.find<AccountService>();
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
@@ -92,7 +94,6 @@ class PgcController
|
||||
}
|
||||
followLoading = true;
|
||||
var res = await FavHttp.favPgc(
|
||||
mid: accountService.mid,
|
||||
type: tabType == HomeTabType.bangumi ? 1 : 2,
|
||||
pn: followPage,
|
||||
);
|
||||
@@ -142,4 +143,15 @@ class PgcController
|
||||
followController?.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
@override
|
||||
void onChangeAccount(bool isLogin) {
|
||||
if (isLogin) {
|
||||
followPage = 1;
|
||||
followEnd = false;
|
||||
queryPgcFollow();
|
||||
} else {
|
||||
followState.value = LoadingState.loading();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/storage_key.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart' hide ContextExtensionss;
|
||||
|
||||
class SearchPage extends StatefulWidget {
|
||||
@@ -397,15 +396,10 @@ class _SearchPageState extends State<SearchPage> {
|
||||
title: '历史记录',
|
||||
toJson: () => jsonEncode(_searchController.historyList),
|
||||
fromJson: (json) {
|
||||
try {
|
||||
final list = List<String>.from(json);
|
||||
_searchController.historyList.value = list;
|
||||
GStorage.historyWord.put('cacheList', list);
|
||||
return true;
|
||||
} catch (e) {
|
||||
SmartDialog.showToast(e.toString());
|
||||
return false;
|
||||
}
|
||||
final list = List<String>.from(json);
|
||||
_searchController.historyList.value = list;
|
||||
GStorage.historyWord.put('cacheList', list);
|
||||
return true;
|
||||
},
|
||||
),
|
||||
),
|
||||
|
||||
@@ -151,30 +151,29 @@ class _SponsorBlockPageState extends State<SponsorBlockPage> {
|
||||
title: Text('用户ID', style: titleStyle),
|
||||
subtitle: Text(_userId, style: subTitleStyle),
|
||||
onTap: () {
|
||||
final key = GlobalKey<FormState>();
|
||||
final key = GlobalKey<FormFieldState<String>>();
|
||||
_textController.text = _userId;
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (_) {
|
||||
return AlertDialog(
|
||||
title: Text('用户ID', style: titleStyle),
|
||||
content: Form(
|
||||
content: TextFormField(
|
||||
key: key,
|
||||
child: TextFormField(
|
||||
minLines: 1,
|
||||
maxLines: 4,
|
||||
autofocus: true,
|
||||
controller: _textController,
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z\d]+')),
|
||||
],
|
||||
validator: (value) {
|
||||
if ((value?.length ?? -1) < 30) {
|
||||
return '用户ID要求至少为30个字符长度的纯字符串';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
minLines: 1,
|
||||
maxLines: 4,
|
||||
autofocus: true,
|
||||
controller: _textController,
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z\d]+')),
|
||||
],
|
||||
decoration: const InputDecoration(errorMaxLines: 2),
|
||||
validator: (value) {
|
||||
if ((value?.length ?? -1) < 30) {
|
||||
return '用户ID要求至少为30个字符长度的纯字符串';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
|
||||
@@ -57,6 +57,7 @@ import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/storage_key.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:canvas_danmaku/canvas_danmaku.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:easy_debounce/easy_throttle.dart';
|
||||
import 'package:fl_chart/fl_chart.dart';
|
||||
@@ -2132,9 +2133,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
Future<void> screenshotWebp() async {
|
||||
final videoInfo = videoDetailController.data;
|
||||
final ids = videoInfo.dash!.video!.map((i) => i.id!).toSet();
|
||||
final video = videoDetailController.findVideoByQa(
|
||||
ids.reduce((p, n) => p < n ? p : n),
|
||||
);
|
||||
final video = videoDetailController.findVideoByQa(ids.min);
|
||||
|
||||
VideoQuality qa = video.quality;
|
||||
String? url = video.baseUrl;
|
||||
@@ -2513,7 +2512,7 @@ Widget buildDmChart(
|
||||
minX: 0,
|
||||
maxX: (dmTrend.length - 1).toDouble(),
|
||||
minY: 0,
|
||||
maxY: dmTrend.reduce((a, b) => a > b ? a : b).toDouble(),
|
||||
maxY: dmTrend.max,
|
||||
lineBarsData: [
|
||||
LineChartBarData(
|
||||
spots: List.generate(
|
||||
|
||||
@@ -1,20 +1,44 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:PiliPlus/models/user/info.dart';
|
||||
import 'package:PiliPlus/utils/storage_pref.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class AccountService extends GetxService {
|
||||
late int mid;
|
||||
late final RxString name;
|
||||
late final RxString face;
|
||||
late final RxBool isLogin;
|
||||
final RxString face = ''.obs;
|
||||
final RxBool isLogin = false.obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
UserInfoData? userInfo = Pref.userInfoCache;
|
||||
mid = userInfo?.mid ?? 0;
|
||||
name = (userInfo?.uname ?? '').obs;
|
||||
face = (userInfo?.face ?? '').obs;
|
||||
isLogin = (userInfo != null).obs;
|
||||
if (userInfo != null) {
|
||||
face.value = userInfo.face ?? '';
|
||||
isLogin.value = true;
|
||||
} else {
|
||||
face.value = '';
|
||||
isLogin.value = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mixin AccountMixin on GetLifeCycleBase {
|
||||
StreamSubscription<bool>? _listener;
|
||||
|
||||
AccountService get accountService => Get.find<AccountService>();
|
||||
|
||||
void onChangeAccount(bool isLogin);
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
_listener = accountService.isLogin.listen(onChangeAccount);
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
_listener?.cancel();
|
||||
_listener = null;
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,9 +106,9 @@ abstract class Accounts {
|
||||
}
|
||||
|
||||
static Future<void> set(AccountType key, Account account) async {
|
||||
await (accountMode[key.index]..type.remove(key)).onChange();
|
||||
final oldAccount = accountMode[key.index]..type.remove(key);
|
||||
accountMode[key.index] = account..type.add(key);
|
||||
await account.onChange();
|
||||
await Future.wait([account.onChange(), oldAccount.onChange()]);
|
||||
if (!account.activated) await Request.buvidActive(account);
|
||||
switch (key) {
|
||||
case AccountType.main:
|
||||
|
||||
@@ -2,19 +2,9 @@ import 'dart:async' show FutureOr;
|
||||
import 'dart:io' show Platform;
|
||||
|
||||
import 'package:PiliPlus/grpc/grpc_req.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/http/user.dart';
|
||||
import 'package:PiliPlus/main.dart';
|
||||
import 'package:PiliPlus/models/common/dynamic/dynamics_type.dart';
|
||||
import 'package:PiliPlus/models/common/home_tab_type.dart';
|
||||
import 'package:PiliPlus/models/user/info.dart';
|
||||
import 'package:PiliPlus/models/user/stat.dart';
|
||||
import 'package:PiliPlus/pages/dynamics/controller.dart';
|
||||
import 'package:PiliPlus/pages/dynamics_tab/controller.dart';
|
||||
import 'package:PiliPlus/pages/live/controller.dart';
|
||||
import 'package:PiliPlus/pages/main/controller.dart';
|
||||
import 'package:PiliPlus/pages/mine/controller.dart';
|
||||
import 'package:PiliPlus/pages/pgc/controller.dart';
|
||||
import 'package:PiliPlus/services/account_service.dart';
|
||||
import 'package:PiliPlus/utils/accounts.dart';
|
||||
import 'package:PiliPlus/utils/accounts/account.dart';
|
||||
@@ -22,11 +12,13 @@ import 'package:PiliPlus/utils/request_utils.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/storage_pref.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:crypto/crypto.dart' show Digest;
|
||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart' as web;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
abstract class LoginUtils {
|
||||
abstract final class LoginUtils {
|
||||
static FutureOr setWebCookie([Account? account]) {
|
||||
if (Platform.isLinux) {
|
||||
return null;
|
||||
@@ -62,48 +54,19 @@ abstract class LoginUtils {
|
||||
if (result.isSuccess) {
|
||||
final UserInfoData data = result.data;
|
||||
if (data.isLogin == true) {
|
||||
Get.find<AccountService>()
|
||||
..mid = data.mid!
|
||||
..name.value = data.uname!
|
||||
..face.value = data.face!
|
||||
..isLogin.value = true;
|
||||
final accountService = Get.find<AccountService>()
|
||||
..face.value = data.face!;
|
||||
|
||||
if (accountService.isLogin.value) {
|
||||
accountService.isLogin.refresh();
|
||||
} else {
|
||||
accountService.isLogin.value = true;
|
||||
}
|
||||
|
||||
SmartDialog.showToast('main登录成功');
|
||||
if (data != Pref.userInfoCache) {
|
||||
await GStorage.userInfo.put('userInfoCache', data);
|
||||
}
|
||||
|
||||
try {
|
||||
Get.find<MineController>().onRefresh();
|
||||
} catch (_) {}
|
||||
|
||||
try {
|
||||
Get.find<DynamicsController>().onRefresh();
|
||||
} catch (_) {}
|
||||
|
||||
for (var item in DynamicsTabType.values) {
|
||||
try {
|
||||
Get.find<DynamicsTabController>(tag: item.name).onRefresh();
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
try {
|
||||
Get.find<LiveController>().onRefresh();
|
||||
} catch (_) {}
|
||||
|
||||
try {
|
||||
Get.find<PgcController>(tag: HomeTabType.bangumi.name)
|
||||
..followPage = 1
|
||||
..followEnd = false
|
||||
..queryPgcFollow();
|
||||
} catch (_) {}
|
||||
|
||||
try {
|
||||
Get.find<PgcController>(tag: HomeTabType.cinema.name)
|
||||
..followPage = 1
|
||||
..followEnd = false
|
||||
..queryPgcFollow();
|
||||
} catch (_) {}
|
||||
}
|
||||
} else {
|
||||
// 获取用户信息失败
|
||||
@@ -115,65 +78,26 @@ abstract class LoginUtils {
|
||||
}
|
||||
}
|
||||
|
||||
static Future<void> onLogoutMain() async {
|
||||
static Future<void> onLogoutMain() {
|
||||
Get.find<AccountService>()
|
||||
..mid = 0
|
||||
..name.value = ''
|
||||
..face.value = ''
|
||||
..isLogin.value = false;
|
||||
|
||||
GrpcReq.updateHeaders(null);
|
||||
|
||||
await Future.wait([
|
||||
return Future.wait([
|
||||
if (!Platform.isLinux)
|
||||
web.CookieManager.instance(
|
||||
webViewEnvironment: webViewEnvironment,
|
||||
).deleteAllCookies(),
|
||||
GStorage.userInfo.delete('userInfoCache'),
|
||||
]);
|
||||
|
||||
try {
|
||||
Get.find<MainController>().setDynCount();
|
||||
} catch (_) {}
|
||||
|
||||
try {
|
||||
Get.find<MineController>()
|
||||
..userInfo.value = UserInfoData()
|
||||
..userStat.value = UserStat()
|
||||
..loadingState.value = LoadingState.loading();
|
||||
// MineController.anonymity.value = false;
|
||||
} catch (_) {}
|
||||
|
||||
try {
|
||||
Get.find<DynamicsController>().onRefresh();
|
||||
} catch (_) {}
|
||||
|
||||
try {
|
||||
Get.find<LiveController>().onRefresh();
|
||||
} catch (_) {}
|
||||
|
||||
for (var item in DynamicsTabType.values) {
|
||||
try {
|
||||
Get.find<DynamicsTabController>(tag: item.name).onRefresh();
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
try {
|
||||
Get.find<PgcController>(tag: HomeTabType.bangumi.name).followState.value =
|
||||
LoadingState.loading();
|
||||
} catch (_) {}
|
||||
|
||||
try {
|
||||
Get.find<PgcController>(tag: HomeTabType.cinema.name).followState.value =
|
||||
LoadingState.loading();
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
static String generateBuvid() {
|
||||
var md5Str = Iterable.generate(
|
||||
32,
|
||||
(_) => Utils.random.nextInt(16).toRadixString(16),
|
||||
).join().toUpperCase();
|
||||
var md5Str = Digest(
|
||||
List.generate(16, (_) => Utils.random.nextInt(256)),
|
||||
).toString();
|
||||
return 'XY${md5Str[2]}${md5Str[12]}${md5Str[22]}$md5Str';
|
||||
}
|
||||
|
||||
@@ -190,31 +114,26 @@ abstract class LoginUtils {
|
||||
|
||||
static String genDeviceId() {
|
||||
// https://github.com/bilive/bilive_client/blob/2873de0532c54832f5464a4c57325ad9af8b8698/bilive/lib/app_client.ts#L62
|
||||
final String yyyyMMddHHmmss = DateTime.now()
|
||||
.toIso8601String()
|
||||
.replaceAll(RegExp(r'[-:TZ]'), '')
|
||||
.substring(0, 14);
|
||||
final time = DateTime.now();
|
||||
|
||||
final String randomHex32 = List.generate(
|
||||
32,
|
||||
(index) => Utils.random.nextInt(16).toRadixString(16),
|
||||
).join();
|
||||
final String randomHex16 = List.generate(
|
||||
16,
|
||||
(index) => Utils.random.nextInt(16).toRadixString(16),
|
||||
).join();
|
||||
final List<int> bytes = [
|
||||
...Iterable.generate(16, (_) => Utils.random.nextInt(256)),
|
||||
_dec2bcd(time.year ~/ 100),
|
||||
_dec2bcd(time.year % 100),
|
||||
_dec2bcd(time.month),
|
||||
_dec2bcd(time.day),
|
||||
_dec2bcd(time.hour),
|
||||
_dec2bcd(time.minute),
|
||||
_dec2bcd(time.second),
|
||||
...Iterable.generate(8, (_) => Utils.random.nextInt(256)),
|
||||
];
|
||||
final check = (bytes.sum & 0xFF).toRadixString(16).padLeft(2, '0');
|
||||
|
||||
final String deviceID = randomHex32 + yyyyMMddHHmmss + randomHex16;
|
||||
return Digest(bytes).toString() + check;
|
||||
}
|
||||
|
||||
final List<int> bytes = RegExp(r'\w{2}')
|
||||
.allMatches(deviceID)
|
||||
.map((match) => int.parse(match.group(0)!, radix: 16))
|
||||
.toList();
|
||||
final int checksumValue = bytes.reduce((a, b) => a + b);
|
||||
final String check = checksumValue
|
||||
.toRadixString(16)
|
||||
.substring(checksumValue.toRadixString(16).length - 2);
|
||||
|
||||
return deviceID + check;
|
||||
static int _dec2bcd(int dec) {
|
||||
assert(0 <= dec && dec < 100);
|
||||
return ((dec ~/ 10) << 4) | (dec % 10);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,10 +72,10 @@ abstract class GStorage {
|
||||
importAllJsonSettings(jsonDecode(data));
|
||||
|
||||
static Future<bool> importAllJsonSettings(Map<String, dynamic> map) async {
|
||||
await setting.clear();
|
||||
await video.clear();
|
||||
await setting.putAll(map[setting.name]);
|
||||
await video.putAll(map[video.name]);
|
||||
await Future.wait([
|
||||
setting.clear().then((_) => setting.putAll(map[setting.name])),
|
||||
video.clear().then((_) => video.putAll(map[video.name])),
|
||||
]);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user