From 7f033570b3b5d57309b98f30e63f34271ce558ff Mon Sep 17 00:00:00 2001 From: lifegpc Date: Thu, 30 May 2024 11:02:08 +0800 Subject: [PATCH] Add log out to user settings page --- lib/globals.dart | 15 +++++++++++--- lib/l10n/app_en.arb | 5 ++++- lib/l10n/app_zh.arb | 5 ++++- lib/pages/settings/user.dart | 38 ++++++++++++++++++++++++++++++++++++ lib/task.dart | 16 +++++++-------- 5 files changed, 66 insertions(+), 13 deletions(-) diff --git a/lib/globals.dart b/lib/globals.dart index 8f89eb7..07e961a 100644 --- a/lib/globals.dart +++ b/lib/globals.dart @@ -332,10 +332,19 @@ void clearAllStates(BuildContext context) { checkAuth(context); } +void clearAllStates2(GoRouterState? state, GoRouter router) { + auth.clear(); + tags.clear(); + tasks.clear(); + checkAuth2(state, router); +} + void checkAuth(BuildContext context) { + checkAuth2(GoRouterState.of(context), GoRouter.of(context)); +} + +void checkAuth2(GoRouterState? state, GoRouter router) { if (!auth.isAuthed && !auth.checked && !auth.isChecking) { - final state = GoRouterState.of(context); - final router = GoRouter.of(context); auth.checkAuth().then((re) { if (!re) { if (auth.status!.noUser && @@ -343,7 +352,7 @@ void checkAuth(BuildContext context) { return; } final loc = auth.status!.noUser ? "/create_root_user" : "/login"; - if (state.path != loc) { + if (state?.path != loc) { router.push(loc); } } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index c58f839..5b88940 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -237,5 +237,8 @@ "oldPassword": "Old password", "newPassword": "New password", "incorrectPassword": "Incorrect password.", - "changedPasswordSuccessfully": "Changed password successfully." + "changedPasswordSuccessfully": "Changed password successfully.", + "logout": "Log out", + "logoutConfirm": "Do you want to log out?", + "failedLogout": "Failed to log out: " } diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 17528e7..a4716d9 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -237,5 +237,8 @@ "oldPassword": "旧密码", "newPassword": "新密码", "incorrectPassword": "不正确的密码。", - "changedPasswordSuccessfully": "修改密码成功。" + "changedPasswordSuccessfully": "修改密码成功。", + "logout": "退出登录", + "logoutConfirm": "是否退出登录", + "failedLogout": "退出登录失败:" } diff --git a/lib/pages/settings/user.dart b/lib/pages/settings/user.dart index d6665a0..122a3da 100644 --- a/lib/pages/settings/user.dart +++ b/lib/pages/settings/user.dart @@ -47,6 +47,22 @@ Future _changeUserPassword( } } +Future _deleteToken(AppLocalizations i18n, GoRouter router) async { + try { + (await api.deleteToken()).unwrap(); + clearAllStates2(null, router); + } catch (e, stack) { + String errmsg = e.toString(); + if (e is (int, String)) { + _log.warning("Failed to delete token: $e"); + } else { + _log.severe("Failed to delete token: $e\n$stack"); + } + final snack = SnackBar(content: Text("${i18n.failedLogout}$errmsg")); + rootScaffoldMessengerKey.currentState?.showSnackBar(snack); + } +} + class _ChangeUsernameDialog extends StatefulWidget { const _ChangeUsernameDialog({this.username}); @@ -254,6 +270,28 @@ class _UserSettingsPage extends State with ThemeModeWidget { padding: const EdgeInsets.only(left: 16), child: UserPermissionsChips( permissions: auth.user!.permissions, readOnly: true)), + ListTile( + leading: const Icon(Icons.logout), + title: Text(i18n.logout), + onTap: () => showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text(i18n.logout), + content: Text(i18n.logoutConfirm), + actions: [ + TextButton( + onPressed: () { + _deleteToken(i18n, GoRouter.of(context)); + context.pop(); + }, + child: Text(i18n.yes)), + TextButton( + onPressed: () { + context.pop(); + }, + child: Text(i18n.no)), + ], + ))), ])); } diff --git a/lib/task.dart b/lib/task.dart index 0e545c0..4de32f5 100644 --- a/lib/task.dart +++ b/lib/task.dart @@ -27,12 +27,14 @@ class TaskManager { bool _needClosed = false; bool _waitClosed = false; bool get closed => _closed; + int _connectId = 0; void clear() { - tasks.clear(); - tasksList.clear(); + _connectId++; _channel?.sink.add("{\"type\":\"close\"}"); _channel?.sink.close(); _channel = null; + tasks.clear(); + tasksList.clear(); _closed = true; } @@ -98,8 +100,8 @@ class TaskManager { Future connect() async { if (auth.canManageTasks != true) return; try { - final url = api.getTaskUrl(); - _channel = await connectWebSocket(url); + final cId = _connectId; + _channel = await connectWebSocket(api.getTaskUrl()); _channel!.stream.listen((event) { try { final data = jsonDecode(event) as Map; @@ -198,8 +200,7 @@ class TaskManager { } }, onError: (e) { _log.warning("Task websocket error: $e"); - final url2 = api.getTaskUrl(); - if (_allowReconnect && !_needClosed && url == url2) { + if (_allowReconnect && !_needClosed && _connectId == cId) { _log.info("Reconnecting to task server in 5 seconds"); _reconnectTimer = Timer(const Duration(seconds: 5), () { _reconnectTimer = null; @@ -212,8 +213,7 @@ class TaskManager { }, onDone: () { _log.warning( "WenSocket closed: ${_channel?.closeCode} ${_channel?.closeReason}"); - final url2 = api.getTaskUrl(); - if (_allowReconnect && !_needClosed && url == url2) { + if (_allowReconnect && !_needClosed && _connectId == cId) { _log.info("Reconnecting to task server in 5 seconds"); _reconnectTimer = Timer(const Duration(seconds: 5), () { _reconnectTimer = null;