Merge pull request #4723 from dignow/fix/user_login_state
Fix/user login state
This commit is contained in:
commit
eb686e2728
@ -3,6 +3,7 @@ import 'package:flutter_hbb/common/formatter/id_formatter.dart';
|
|||||||
import 'package:flutter_hbb/common/widgets/peer_card.dart';
|
import 'package:flutter_hbb/common/widgets/peer_card.dart';
|
||||||
import 'package:flutter_hbb/common/widgets/peers_view.dart';
|
import 'package:flutter_hbb/common/widgets/peers_view.dart';
|
||||||
import 'package:flutter_hbb/desktop/widgets/popup_menu.dart';
|
import 'package:flutter_hbb/desktop/widgets/popup_menu.dart';
|
||||||
|
import 'package:flutter_hbb/models/state_model.dart';
|
||||||
import '../../consts.dart';
|
import '../../consts.dart';
|
||||||
import '../../desktop/widgets/material_mod_popup_menu.dart' as mod_menu;
|
import '../../desktop/widgets/material_mod_popup_menu.dart' as mod_menu;
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
@ -29,15 +30,18 @@ class _AddressBookState extends State<AddressBook> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => FutureBuilder<Widget>(
|
Widget build(BuildContext context) => Obx(() => Offstage(
|
||||||
future: buildBody(context),
|
offstage: stateGlobal.svcStatus.value != SvcStatus.ready,
|
||||||
builder: (context, snapshot) {
|
child: FutureBuilder<Widget>(
|
||||||
if (snapshot.hasData) {
|
future: buildBody(context),
|
||||||
return snapshot.data!;
|
builder: (context, snapshot) {
|
||||||
} else {
|
if (snapshot.hasData) {
|
||||||
return const Offstage();
|
return snapshot.data!;
|
||||||
}
|
} else {
|
||||||
});
|
return const Offstage();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
|
||||||
Future<Widget> buildBody(BuildContext context) async {
|
Future<Widget> buildBody(BuildContext context) async {
|
||||||
return Obx(() {
|
return Obx(() {
|
||||||
@ -54,6 +58,9 @@ class _AddressBookState extends State<AddressBook> {
|
|||||||
if (gFFI.abModel.abError.isNotEmpty) {
|
if (gFFI.abModel.abError.isNotEmpty) {
|
||||||
return _buildShowError(gFFI.abModel.abError.value);
|
return _buildShowError(gFFI.abModel.abError.value);
|
||||||
}
|
}
|
||||||
|
if (gFFI.abModel.fromServer.isFalse) {
|
||||||
|
return Offstage();
|
||||||
|
}
|
||||||
return isDesktop
|
return isDesktop
|
||||||
? _buildAddressBookDesktop()
|
? _buildAddressBookDesktop()
|
||||||
: _buildAddressBookMobile();
|
: _buildAddressBookMobile();
|
||||||
|
@ -96,7 +96,7 @@ class ConfigOP {
|
|||||||
class WidgetOP extends StatefulWidget {
|
class WidgetOP extends StatefulWidget {
|
||||||
final ConfigOP config;
|
final ConfigOP config;
|
||||||
final RxString curOP;
|
final RxString curOP;
|
||||||
final Function(String) cbLogin;
|
final Function(Map<String, dynamic>) cbLogin;
|
||||||
const WidgetOP({
|
const WidgetOP({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.config,
|
required this.config,
|
||||||
@ -153,9 +153,8 @@ class _WidgetOPState extends State<WidgetOP> {
|
|||||||
}
|
}
|
||||||
if (authBody != null) {
|
if (authBody != null) {
|
||||||
_updateTimer?.cancel();
|
_updateTimer?.cancel();
|
||||||
final String username = authBody['user']['name'];
|
|
||||||
widget.curOP.value = '';
|
widget.curOP.value = '';
|
||||||
widget.cbLogin(username);
|
widget.cbLogin(authBody as Map<String, dynamic>);
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -255,7 +254,7 @@ class _WidgetOPState extends State<WidgetOP> {
|
|||||||
class LoginWidgetOP extends StatelessWidget {
|
class LoginWidgetOP extends StatelessWidget {
|
||||||
final List<ConfigOP> ops;
|
final List<ConfigOP> ops;
|
||||||
final RxString curOP;
|
final RxString curOP;
|
||||||
final Function(String) cbLogin;
|
final Function(Map<String, dynamic>) cbLogin;
|
||||||
|
|
||||||
LoginWidgetOP({
|
LoginWidgetOP({
|
||||||
Key? key,
|
Key? key,
|
||||||
@ -368,7 +367,8 @@ const kAuthReqTypeOidc = 'oidc/';
|
|||||||
/// common login dialog for desktop
|
/// common login dialog for desktop
|
||||||
/// call this directly
|
/// call this directly
|
||||||
Future<bool?> loginDialog() async {
|
Future<bool?> loginDialog() async {
|
||||||
var username = TextEditingController();
|
var username =
|
||||||
|
TextEditingController(text: UserModel.getLocalUserInfo()?['name'] ?? '');
|
||||||
var password = TextEditingController();
|
var password = TextEditingController();
|
||||||
final userFocusNode = FocusNode()..requestFocus();
|
final userFocusNode = FocusNode()..requestFocus();
|
||||||
Timer(Duration(milliseconds: 100), () => userFocusNode..requestFocus());
|
Timer(Duration(milliseconds: 100), () => userFocusNode..requestFocus());
|
||||||
@ -480,8 +480,17 @@ Future<bool?> loginDialog() async {
|
|||||||
.where((op) => oidcOptions.contains(op.op.toLowerCase()))
|
.where((op) => oidcOptions.contains(op.op.toLowerCase()))
|
||||||
.toList(),
|
.toList(),
|
||||||
curOP: curOP,
|
curOP: curOP,
|
||||||
cbLogin: (String username) {
|
cbLogin: (Map<String, dynamic> authBody) {
|
||||||
gFFI.userModel.userName.value = username;
|
try {
|
||||||
|
final loginResp =
|
||||||
|
gFFI.userModel.getLoginResponseFromAuthBody(authBody);
|
||||||
|
if (loginResp.access_token != null) {
|
||||||
|
bind.mainSetLocalOption(
|
||||||
|
key: 'access_token', value: loginResp.access_token!);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('Failed too parse oidc login body: "$authBody"');
|
||||||
|
}
|
||||||
close(true);
|
close(true);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hbb/common/hbbs/hbbs.dart';
|
import 'package:flutter_hbb/common/hbbs/hbbs.dart';
|
||||||
import 'package:flutter_hbb/common/widgets/peers_view.dart';
|
import 'package:flutter_hbb/common/widgets/peers_view.dart';
|
||||||
|
import 'package:flutter_hbb/models/state_model.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
import '../../common.dart';
|
import '../../common.dart';
|
||||||
@ -26,15 +27,20 @@ class _MyGroupState extends State<MyGroup> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => FutureBuilder<Widget>(
|
Widget build(BuildContext context) {
|
||||||
future: buildBody(context),
|
return Obx(() => Offstage(
|
||||||
builder: (context, snapshot) {
|
offstage: stateGlobal.svcStatus.value != SvcStatus.ready,
|
||||||
if (snapshot.hasData) {
|
child: FutureBuilder<Widget>(
|
||||||
return snapshot.data!;
|
future: buildBody(context),
|
||||||
} else {
|
builder: (context, snapshot) {
|
||||||
return const Offstage();
|
if (snapshot.hasData) {
|
||||||
}
|
return snapshot.data!;
|
||||||
});
|
} else {
|
||||||
|
return const Offstage();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
Future<Widget> buildBody(BuildContext context) async {
|
Future<Widget> buildBody(BuildContext context) async {
|
||||||
return Obx(() {
|
return Obx(() {
|
||||||
|
@ -42,7 +42,6 @@ class _ConnectionPageState extends State<ConnectionPage>
|
|||||||
final FocusNode _idFocusNode = FocusNode();
|
final FocusNode _idFocusNode = FocusNode();
|
||||||
|
|
||||||
var svcStopped = Get.find<RxBool>(tag: 'stop-service');
|
var svcStopped = Get.find<RxBool>(tag: 'stop-service');
|
||||||
var svcStatusCode = 0.obs;
|
|
||||||
var svcIsUsingPublicServer = true.obs;
|
var svcIsUsingPublicServer = true.obs;
|
||||||
|
|
||||||
bool isWindowMinimized = false;
|
bool isWindowMinimized = false;
|
||||||
@ -253,9 +252,9 @@ class _ConnectionPageState extends State<ConnectionPage>
|
|||||||
width: 8,
|
width: 8,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(4),
|
borderRadius: BorderRadius.circular(4),
|
||||||
color: svcStopped.value || svcStatusCode.value == 0
|
color: svcStopped.value || stateGlobal.svcStatus.value == SvcStatus.connecting
|
||||||
? kColorWarn
|
? kColorWarn
|
||||||
: (svcStatusCode.value == 1
|
: (stateGlobal.svcStatus.value == SvcStatus.ready
|
||||||
? Color.fromARGB(255, 50, 190, 166)
|
? Color.fromARGB(255, 50, 190, 166)
|
||||||
: Color.fromARGB(255, 224, 79, 95)),
|
: Color.fromARGB(255, 224, 79, 95)),
|
||||||
),
|
),
|
||||||
@ -263,9 +262,9 @@ class _ConnectionPageState extends State<ConnectionPage>
|
|||||||
Text(
|
Text(
|
||||||
svcStopped.value
|
svcStopped.value
|
||||||
? translate("Service is not running")
|
? translate("Service is not running")
|
||||||
: svcStatusCode.value == 0
|
: stateGlobal.svcStatus.value == SvcStatus.connecting
|
||||||
? translate("connecting_status")
|
? translate("connecting_status")
|
||||||
: svcStatusCode.value == -1
|
: stateGlobal.svcStatus.value == SvcStatus.notReady
|
||||||
? translate("not_ready_status")
|
? translate("not_ready_status")
|
||||||
: translate('Ready'),
|
: translate('Ready'),
|
||||||
style: TextStyle(fontSize: em)),
|
style: TextStyle(fontSize: em)),
|
||||||
@ -286,7 +285,7 @@ class _ConnectionPageState extends State<ConnectionPage>
|
|||||||
Flexible(
|
Flexible(
|
||||||
child: Offstage(
|
child: Offstage(
|
||||||
offstage: !(!svcStopped.value &&
|
offstage: !(!svcStopped.value &&
|
||||||
svcStatusCode.value == 1 &&
|
stateGlobal.svcStatus.value == SvcStatus.ready &&
|
||||||
svcIsUsingPublicServer.value),
|
svcIsUsingPublicServer.value),
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
@ -330,7 +329,25 @@ class _ConnectionPageState extends State<ConnectionPage>
|
|||||||
updateStatus() async {
|
updateStatus() async {
|
||||||
final status =
|
final status =
|
||||||
jsonDecode(await bind.mainGetConnectStatus()) as Map<String, dynamic>;
|
jsonDecode(await bind.mainGetConnectStatus()) as Map<String, dynamic>;
|
||||||
svcStatusCode.value = status["status_num"];
|
final statusNum = status['status_num'] as int;
|
||||||
|
final preStatus = stateGlobal.svcStatus.value;
|
||||||
|
if (statusNum == 0) {
|
||||||
|
stateGlobal.svcStatus.value = SvcStatus.connecting;
|
||||||
|
} else if (statusNum == -1) {
|
||||||
|
stateGlobal.svcStatus.value = SvcStatus.notReady;
|
||||||
|
} else if (statusNum == 1) {
|
||||||
|
stateGlobal.svcStatus.value = SvcStatus.ready;
|
||||||
|
if (preStatus != SvcStatus.ready) {
|
||||||
|
gFFI.userModel.refreshCurrentUser();
|
||||||
|
gFFI.groupModel.pull();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stateGlobal.svcStatus.value = SvcStatus.notReady;
|
||||||
|
}
|
||||||
|
if (stateGlobal.svcStatus.value != SvcStatus.ready) {
|
||||||
|
gFFI.userModel.isAdmin.value = false;
|
||||||
|
gFFI.groupModel.reset();
|
||||||
|
}
|
||||||
svcIsUsingPublicServer.value = await bind.mainIsUsingPublicServer();
|
svcIsUsingPublicServer.value = await bind.mainIsUsingPublicServer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,13 @@ import 'package:http/http.dart' as http;
|
|||||||
import '../common.dart';
|
import '../common.dart';
|
||||||
|
|
||||||
class AbModel {
|
class AbModel {
|
||||||
var abLoading = false.obs;
|
final abLoading = false.obs;
|
||||||
var abError = "".obs;
|
final abError = "".obs;
|
||||||
var tags = [].obs;
|
final tags = [].obs;
|
||||||
var peers = List<Peer>.empty(growable: true).obs;
|
final RxBool fromServer = false.obs;
|
||||||
|
final peers = List<Peer>.empty(growable: true).obs;
|
||||||
|
|
||||||
var selectedTags = List<String>.empty(growable: true).obs;
|
final selectedTags = List<String>.empty(growable: true).obs;
|
||||||
|
|
||||||
WeakReference<FFI> parent;
|
WeakReference<FFI> parent;
|
||||||
|
|
||||||
@ -49,8 +50,10 @@ class AbModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fromServer.value = true;
|
||||||
return resp.body;
|
return resp.body;
|
||||||
} else {
|
} else {
|
||||||
|
fromServer.value = true;
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -6,6 +6,8 @@ import 'package:get/get.dart';
|
|||||||
|
|
||||||
import '../consts.dart';
|
import '../consts.dart';
|
||||||
|
|
||||||
|
enum SvcStatus { notReady, connecting, ready }
|
||||||
|
|
||||||
class StateGlobal {
|
class StateGlobal {
|
||||||
int _windowId = -1;
|
int _windowId = -1;
|
||||||
bool _fullscreen = false;
|
bool _fullscreen = false;
|
||||||
@ -16,6 +18,7 @@ class StateGlobal {
|
|||||||
final RxDouble _windowBorderWidth = RxDouble(kWindowBorderWidth);
|
final RxDouble _windowBorderWidth = RxDouble(kWindowBorderWidth);
|
||||||
final RxBool showRemoteToolBar = false.obs;
|
final RxBool showRemoteToolBar = false.obs;
|
||||||
final RxInt displaysCount = 0.obs;
|
final RxInt displaysCount = 0.obs;
|
||||||
|
final svcStatus = SvcStatus.notReady.obs;
|
||||||
|
|
||||||
// Use for desktop -> remote toolbar -> resolution
|
// Use for desktop -> remote toolbar -> resolution
|
||||||
final Map<String, Map<int, String?>> _lastResolutionGroupValues = {};
|
final Map<String, Map<int, String?>> _lastResolutionGroupValues = {};
|
||||||
|
@ -24,6 +24,7 @@ class UserModel {
|
|||||||
await _updateOtherModels();
|
await _updateOtherModels();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
_updateLocalUserInfo();
|
||||||
final url = await bind.mainGetApiServer();
|
final url = await bind.mainGetApiServer();
|
||||||
final body = {
|
final body = {
|
||||||
'id': await bind.mainGetMyId(),
|
'id': await bind.mainGetMyId(),
|
||||||
@ -48,7 +49,7 @@ class UserModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final user = UserPayload.fromJson(data);
|
final user = UserPayload.fromJson(data);
|
||||||
await _parseAndUpdateUser(user);
|
_parseAndUpdateUser(user);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Failed to refreshCurrentUser: $e');
|
print('Failed to refreshCurrentUser: $e');
|
||||||
} finally {
|
} finally {
|
||||||
@ -56,6 +57,22 @@ class UserModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Map<String, dynamic>? getLocalUserInfo() {
|
||||||
|
try {
|
||||||
|
return json.decode(bind.mainGetLocalOption(key: 'user_info'));
|
||||||
|
} catch (e) {
|
||||||
|
print('Failed to get local user info: $e');
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateLocalUserInfo() {
|
||||||
|
final userInfo = getLocalUserInfo();
|
||||||
|
if (userInfo != null) {
|
||||||
|
userName.value = userInfo['name'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> reset() async {
|
Future<void> reset() async {
|
||||||
await bind.mainSetLocalOption(key: 'access_token', value: '');
|
await bind.mainSetLocalOption(key: 'access_token', value: '');
|
||||||
await gFFI.abModel.reset();
|
await gFFI.abModel.reset();
|
||||||
@ -64,7 +81,7 @@ class UserModel {
|
|||||||
gFFI.peerTabModel.check_dynamic_tabs();
|
gFFI.peerTabModel.check_dynamic_tabs();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _parseAndUpdateUser(UserPayload user) async {
|
_parseAndUpdateUser(UserPayload user) {
|
||||||
userName.value = user.name;
|
userName.value = user.name;
|
||||||
isAdmin.value = user.isAdmin;
|
isAdmin.value = user.isAdmin;
|
||||||
}
|
}
|
||||||
@ -110,11 +127,14 @@ class UserModel {
|
|||||||
print("login: jsonDecode resp body failed: ${e.toString()}");
|
print("login: jsonDecode resp body failed: ${e.toString()}");
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resp.statusCode != 200) {
|
if (resp.statusCode != 200) {
|
||||||
throw RequestException(resp.statusCode, body['error'] ?? '');
|
throw RequestException(resp.statusCode, body['error'] ?? '');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return getLoginResponseFromAuthBody(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
LoginResponse getLoginResponseFromAuthBody(Map<String, dynamic> body) {
|
||||||
final LoginResponse loginResponse;
|
final LoginResponse loginResponse;
|
||||||
try {
|
try {
|
||||||
loginResponse = LoginResponse.fromJson(body);
|
loginResponse = LoginResponse.fromJson(body);
|
||||||
@ -124,7 +144,7 @@ class UserModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (loginResponse.user != null) {
|
if (loginResponse.user != null) {
|
||||||
await _parseAndUpdateUser(loginResponse.user!);
|
_parseAndUpdateUser(loginResponse.user!);
|
||||||
}
|
}
|
||||||
|
|
||||||
return loginResponse;
|
return loginResponse;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user