You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

227 lines
5.8 KiB
Dart

2 years ago
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_web_browser/flutter_web_browser.dart';
2 years ago
import 'package:get/get.dart';
import 'package:isekai_wiki/api/mw/user.dart';
import 'package:isekai_wiki/global.dart';
import 'package:isekai_wiki/utils/dialog.dart';
2 years ago
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
@JsonSerializable()
class UserInfo {
int userId;
String userName;
String? nickName;
Map<int, String>? avatarUrlSet;
2 years ago
UserInfo({
required this.userId,
required this.userName,
this.nickName,
this.avatarUrlSet,
});
2 years ago
factory UserInfo.fromJson(Map<String, dynamic> json) =>
_$UserInfoFromJson(json);
2 years ago
Map<String, dynamic> toJson() => _$UserInfoToJson(this);
}
class UserController extends GetxController {
bool _ignoreSave = false;
2 years ago
var authProcessing = false.obs;
var loginRequestToken = "".obs;
2 years ago
var userId = 0.obs;
2 years ago
var userName = "".obs;
var nickName = "".obs;
var avatarUrlSet = RxMap<int, String>({});
2 years ago
bool get isLoggedIn {
return userId.value > 0;
}
2 years ago
String get getDisplayName {
return nickName.isNotEmpty ? nickName.string : userName.string;
}
@override
void onInit() async {
super.onInit();
2 years ago
loadFromStorage();
updateProfile();
ever(loginRequestToken, (String token) {
saveToStorage();
});
2 years ago
}
/// 更新用户资料,并检测登录状态
Future<void> updateProfile() async {
var userInfoMWRes = await MWApiUser.getCurrentUserInfo();
if (!userInfoMWRes.ok) {
if (kDebugMode) {
print("Cannot update profile of current user");
print(userInfoMWRes.errorList);
}
}
var userInfoRes = userInfoMWRes.data!;
nickName.value = userInfoRes.userinfo.realname ?? "";
if (userInfoRes.useravatar != null) {
avatarUrlSet.value = userInfoRes.useravatar!;
}
}
String? getAvatar(int size) {
if (avatarUrlSet.isEmpty) {
return null;
}
for (var imgSize in avatarUrlSet.keys) {
if (size < imgSize) {
return avatarUrlSet[size];
}
}
return avatarUrlSet.values.last;
}
2 years ago
/// 从本地存储读取
void loadFromStorage() {
2 years ago
try {
final prefs = Global.sharedPreferences!;
2 years ago
var userInfoJson = prefs.getString("userInfo");
if (userInfoJson == null) return;
var userInfoObject = jsonDecode(userInfoJson);
if (userInfoObject == null) return;
var userInfo = UserInfo.fromJson(userInfoObject);
_ignoreSave = true;
2 years ago
userId.value = userInfo.userId;
userName.value = userInfo.userName;
nickName.value = userInfo.nickName ?? "";
avatarUrlSet.value = userInfo.avatarUrlSet ?? {};
_ignoreSave = false;
var savedLoginRequestToken = prefs.getString("loginRequestToken");
if (savedLoginRequestToken != null) {
_ignoreSave = true;
loginRequestToken.value = savedLoginRequestToken;
_ignoreSave = false;
}
2 years ago
} catch (ex) {
if (kDebugMode) {
print(ex);
}
} finally {
_ignoreSave = false;
2 years ago
}
}
/// 保存到本地存储
void saveToStorage() {
if (_ignoreSave) return;
final prefs = Global.sharedPreferences!;
2 years ago
var userInfo = UserInfo(
userId: userId.value,
userName: userName.value,
nickName: nickName.isNotEmpty ? nickName.value : null,
avatarUrlSet: avatarUrlSet.isNotEmpty ? avatarUrlSet : null,
2 years ago
);
var userInfoJson = jsonEncode(userInfo.toJson());
prefs.setString("userInfo", userInfoJson);
if (loginRequestToken.isNotEmpty) {
prefs.setString("loginRequestToken", loginRequestToken.value);
} else if (prefs.containsKey("loginRequestToken")) {
prefs.remove("loginRequestToken");
}
}
/// 开始登录流程
/// 从服务器获取loginRequestToken
Future<void> startAuthFlow() async {
authProcessing.value = true;
var startAuthRes = await MWApiUser.startAuth();
if (!startAuthRes.ok) {
authProcessing.value = false;
alert(Get.overlayContext!, startAuthRes.errorList?[0].info ?? "未知错误",
title: "错误");
return;
}
var startAuthInfo = startAuthRes.data!;
loginRequestToken.value = startAuthInfo.loginRequestKey;
await FlutterWebBrowser.openWebPage(
url: startAuthInfo.loginUrl,
customTabsOptions: const CustomTabsOptions(
defaultColorSchemeParams: CustomTabsColorSchemeParams(
toolbarColor: Color.fromRGBO(33, 37, 41, 1),
),
shareState: CustomTabsShareState.off,
showTitle: true,
),
safariVCOptions: const SafariViewControllerOptions(
barCollapsingEnabled: true,
));
}
// 尝试通过登录请求Token完成登录
Future<void> attemptFinishAuth() async {
if (loginRequestToken.isEmpty) {
authProcessing.value = false;
return;
}
var attemptAuthRes = await MWApiUser.attemptAuth(loginRequestToken.value);
if (!attemptAuthRes.ok) {
authProcessing.value = false;
alert(Get.overlayContext!, attemptAuthRes.errorList?[0].info ?? "未知错误",
title: "错误");
return;
}
var attemptAuthInfo = attemptAuthRes.data!;
if (attemptAuthInfo.status == "pending") {
authProcessing.value = false;
loginRequestToken.value = "";
alert(Get.overlayContext!, "已取消登录", title: "提示");
return;
} else if (attemptAuthInfo.status == "success") {
userId.value = attemptAuthInfo.userid!;
userName.value = attemptAuthInfo.username!;
try {
await updateProfile();
} catch (err) {
err.printError(info: 'Cannot update profile after auth');
}
authProcessing.value = false;
saveToStorage();
}
2 years ago
}
Future<void> logout() async {}
2 years ago
}