нахуевертил
This commit is contained in:
+12
-4
@@ -32,6 +32,7 @@ class Api {
|
||||
final _stateController = StreamController<SessionState>.broadcast();
|
||||
final _sessionExpiredController =
|
||||
StreamController<SessionExpiredException>.broadcast();
|
||||
final _handshakeSuccessController = StreamController<String>.broadcast();
|
||||
Map<dynamic, dynamic>? _userAgent;
|
||||
|
||||
Map<dynamic, dynamic>? get userAgent => _userAgent;
|
||||
@@ -44,6 +45,8 @@ class Api {
|
||||
Stream<SessionState> get stateStream => _stateController.stream;
|
||||
Stream<SessionExpiredException> get sessionExpiredStream =>
|
||||
_sessionExpiredController.stream;
|
||||
Stream<String> get handshakeSuccessStream =>
|
||||
_handshakeSuccessController.stream;
|
||||
SessionState get state => _sessionState;
|
||||
|
||||
StreamSubscription<Uint8List>? _dataSubscription;
|
||||
@@ -93,6 +96,12 @@ class Api {
|
||||
_setSessionState(SessionState.online);
|
||||
_startPinging();
|
||||
logger.i('Сессия онлайн, хэндшейк ок');
|
||||
_handshakeSuccessController.add(
|
||||
response.payload['device_name'] as String? ?? 'Unknown',
|
||||
);
|
||||
if (_onReconnectCallback != null) {
|
||||
_onReconnectCallback!();
|
||||
}
|
||||
} else {
|
||||
logger.e('Хэндшейк отклонён: ${response.payload}');
|
||||
}
|
||||
@@ -254,7 +263,8 @@ class Api {
|
||||
await for (final packet in _receiver.feed(data)) {
|
||||
if (packet.isError &&
|
||||
packet.payload is Map &&
|
||||
packet.payload['message'] == 'FAIL_LOGIN_TOKEN') {
|
||||
(packet.payload['message'] == 'FAIL_LOGIN_TOKEN' ||
|
||||
packet.payload['message'] == 'FAIL_WRONG_PASSWORD')) {
|
||||
_sessionExpiredController.add(
|
||||
SessionExpiredException(messageFromErrorPayload(packet.payload)),
|
||||
);
|
||||
@@ -277,13 +287,11 @@ class Api {
|
||||
_socketStateSubscription = null;
|
||||
_receiver.reset();
|
||||
_dispatcher.clearPending();
|
||||
_handshakeSuccessController.add('disconnected');
|
||||
}
|
||||
|
||||
Future<void> reconnectAndLogin() async {
|
||||
await connect();
|
||||
if (_sessionState == SessionState.online && _onReconnectCallback != null) {
|
||||
_onReconnectCallback!();
|
||||
}
|
||||
}
|
||||
|
||||
void Function()? _onReconnectCallback;
|
||||
|
||||
@@ -1022,7 +1022,9 @@ class AccountModule {
|
||||
void _checkPacketError(Packet packet, String method) {
|
||||
if (packet.isError) {
|
||||
final payload = packet.payload;
|
||||
if (payload is Map && payload['message'] == 'FAIL_LOGIN_TOKEN') {
|
||||
if (payload is Map &&
|
||||
(payload['message'] == 'FAIL_LOGIN_TOKEN' ||
|
||||
payload['message'] == 'FAIL_WRONG_PASSWORD')) {
|
||||
throw SessionExpiredException(messageFromErrorPayload(payload));
|
||||
}
|
||||
throw PacketError(messageFromErrorPayload(payload));
|
||||
|
||||
@@ -65,6 +65,10 @@ class SessionExpiredException extends PacketError {
|
||||
|
||||
String messageFromErrorPayload(dynamic payload) {
|
||||
if (payload is Map) {
|
||||
final msg = payload['message'];
|
||||
if (msg == 'FAIL_WRONG_PASSWORD' || msg == 'FAIL_LOGIN_TOKEN') {
|
||||
return 'Ваш токен был отклонён сервером, хм... Попробуйте войти ещё раз.';
|
||||
}
|
||||
for (final key in ['localizedMessage', 'message', 'title']) {
|
||||
final v = payload[key];
|
||||
if (v is String && v.trim().isNotEmpty) return v.trim();
|
||||
|
||||
@@ -199,7 +199,20 @@ class _ChatListScreenState extends State<ChatListScreen>
|
||||
|
||||
Future<void> _reloadChatsAndFolders() async {
|
||||
final p = await AppDatabase.loadActiveProfile();
|
||||
if (p != null) {
|
||||
if (p == null) {
|
||||
_syncFolderChatScrollControllersForCount(1);
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_folders = [];
|
||||
_selectedFolderId = null;
|
||||
_foldersListKnown = null;
|
||||
_isInitialLoading = false;
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final chats = await ChatsModule.getChats(p.id);
|
||||
var folders = await FoldersModule.loadFolders(p.id);
|
||||
final foldersKnown = await FoldersModule.hasReceivedFoldersList(p.id);
|
||||
@@ -244,7 +257,7 @@ class _ChatListScreenState extends State<ChatListScreen>
|
||||
_jumpFolderPageToSelection();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
} catch (_) {
|
||||
_syncFolderChatScrollControllersForCount(1);
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
@@ -253,6 +266,9 @@ class _ChatListScreenState extends State<ChatListScreen>
|
||||
_foldersListKnown = null;
|
||||
_isInitialLoading = false;
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
if (mounted) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!mounted) return;
|
||||
_jumpFolderPageToSelection();
|
||||
|
||||
@@ -9,8 +9,10 @@ import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../../../core/config/device_presets.dart';
|
||||
import '../../../core/storage/spoofing_service.dart';
|
||||
import '../../../core/storage/token_storage.dart';
|
||||
import '../../../l10n/app_localizations.dart';
|
||||
import '../../../main.dart';
|
||||
import '../auth/login_screen.dart';
|
||||
|
||||
enum SpoofingMethod { partial, full }
|
||||
|
||||
@@ -127,19 +129,10 @@ class _SpoofScreenState extends State<SpoofScreen> {
|
||||
_deviceNameController.text =
|
||||
'${androidInfo.manufacturer} ${androidInfo.model}';
|
||||
_osVersionController.text = 'Android ${androidInfo.version.release}';
|
||||
_selectedDeviceType = 'ANDROID';
|
||||
_selectedArch = androidInfo.supportedAbis.isNotEmpty
|
||||
? androidInfo.supportedAbis.first
|
||||
: 'arm64-v8a';
|
||||
_buildNumberController.text = '$_hardcodedBuildNumber';
|
||||
} else if (Platform.isIOS) {
|
||||
final iosInfo = await deviceInfo.iosInfo;
|
||||
_deviceNameController.text = iosInfo.name;
|
||||
_osVersionController.text =
|
||||
'${iosInfo.systemName} ${iosInfo.systemVersion}';
|
||||
_selectedDeviceType = 'IOS';
|
||||
_selectedArch = 'arm64';
|
||||
_buildNumberController.text = '$_hardcodedBuildNumber';
|
||||
} else {
|
||||
await _applyGeneratedData();
|
||||
}
|
||||
@@ -168,15 +161,7 @@ class _SpoofScreenState extends State<SpoofScreen> {
|
||||
_appVersionController.text = _hardcodedVersion;
|
||||
_deviceIdController.text = _generateDeviceId();
|
||||
|
||||
_selectedDeviceType = preset.deviceType;
|
||||
|
||||
if (preset.deviceType == 'ANDROID') {
|
||||
_selectedArch = 'arm64-v8a';
|
||||
} else if (preset.deviceType == 'IOS') {
|
||||
_selectedArch = 'arm64';
|
||||
} else {
|
||||
_selectedArch = 'x86_64';
|
||||
}
|
||||
_selectedArch = 'arm64-v8a';
|
||||
_buildNumberController.text = '$_hardcodedBuildNumber';
|
||||
|
||||
if (_selectedMethod == SpoofingMethod.full) {
|
||||
@@ -247,32 +232,76 @@ class _SpoofScreenState extends State<SpoofScreen> {
|
||||
|
||||
if (!mounted) return;
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
final confirmed = await showDialog<bool>(
|
||||
final confirmed = await showDialog<String>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text(l10n.spoofDialogApplyTitle),
|
||||
content: Text(l10n.spoofDialogApplyContent),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(l10n.spoofDialogApplyContent),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
l10n.spoofDialogApplyWarning,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.error,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(false),
|
||||
onPressed: () => Navigator.of(context).pop('cancel'),
|
||||
child: Text(l10n.spoofDialogApplyDeny),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop('relogin'),
|
||||
child: Text(l10n.spoofDialogReloginConfirm),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () => Navigator.of(context).pop(true),
|
||||
onPressed: () => Navigator.of(context).pop('apply'),
|
||||
child: Text(l10n.spoofDialogApplyConfirm),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
if (confirmed != true || !mounted) return;
|
||||
if (!mounted || confirmed == null) return;
|
||||
|
||||
if (confirmed == 'relogin') {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await _saveAllData(prefs);
|
||||
await api.disconnect();
|
||||
final accountId = await TokenStorage.getActiveAccountId();
|
||||
if (accountId != null) {
|
||||
await TokenStorage.deleteToken(accountId);
|
||||
}
|
||||
await prefs.setBool('spoofing_enabled', true);
|
||||
await api.connect();
|
||||
if (mounted) {
|
||||
final navState = KometApp.navigatorKey.currentState;
|
||||
if (navState != null) {
|
||||
await navState.pushAndRemoveUntil(
|
||||
MaterialPageRoute(builder: (_) => const LoginScreen()),
|
||||
(route) => false,
|
||||
);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (confirmed != 'apply') return;
|
||||
|
||||
await _saveAllData(prefs);
|
||||
|
||||
try {
|
||||
await api.disconnect();
|
||||
await api.connect();
|
||||
if (mounted) Navigator.of(context).pop();
|
||||
if (mounted && Navigator.of(context).canPop()) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
@@ -452,29 +481,18 @@ class _SpoofScreenState extends State<SpoofScreen> {
|
||||
text: l10n.spoofDeviceTypeDescription,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_buildChipSelector<String>(
|
||||
options: const [
|
||||
_ChipOption('ANDROID', 'ANDROID', Icons.android_outlined),
|
||||
_ChipOption('IOS', 'iOS', Icons.phone_iphone_outlined),
|
||||
_ChipOption(
|
||||
'DESKTOP',
|
||||
Row(
|
||||
children: [
|
||||
_buildDisabledChip('ANDROID', Icons.android_outlined, theme),
|
||||
const SizedBox(width: 8),
|
||||
_buildDisabledChip('iOS', Icons.phone_iphone_outlined, theme),
|
||||
const SizedBox(width: 8),
|
||||
_buildDisabledChip(
|
||||
'Desktop',
|
||||
Icons.desktop_windows_outlined,
|
||||
theme,
|
||||
),
|
||||
],
|
||||
selected: _selectedDeviceType,
|
||||
onSelected: (value) {
|
||||
setState(() {
|
||||
_selectedDeviceType = value;
|
||||
if (value == 'ANDROID') {
|
||||
_selectedArch = 'arm64-v8a';
|
||||
} else if (value == 'IOS') {
|
||||
_selectedArch = 'arm64';
|
||||
} else {
|
||||
_selectedArch = 'x86_64';
|
||||
}
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -482,6 +500,15 @@ class _SpoofScreenState extends State<SpoofScreen> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDisabledChip(String label, IconData icon, ThemeData theme) {
|
||||
return Chip(
|
||||
label: Text(label),
|
||||
avatar: Icon(icon, size: 18, color: theme.colorScheme.onSurfaceVariant),
|
||||
backgroundColor: theme.colorScheme.surfaceContainerHighest,
|
||||
side: BorderSide(color: theme.colorScheme.outlineVariant),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildDescriptionTile({
|
||||
required IconData icon,
|
||||
required Color color,
|
||||
|
||||
+7
-1
@@ -64,7 +64,7 @@
|
||||
"spoofMethodPartialDescription": "Recommended method. Random data is used, but your real timezone and locale are kept for plausibility.",
|
||||
"spoofMethodFullDescription": "All data including timezone and locale is generated randomly. Use this method at your own risk!",
|
||||
"spoofDeviceTypeTitle": "Device type",
|
||||
"spoofDeviceTypeDescription": "Choose a device type for preset generation. Tapping \"Generate\" will only use presets of the selected type.",
|
||||
"spoofDeviceTypeDescription": "This field is not changeable, to avoid token association issues",
|
||||
"spoofDeviceTypeLabel": "Device type",
|
||||
"spoofMainSectionTitle": "Main data",
|
||||
"spoofFieldDeviceName": "Device name",
|
||||
@@ -88,6 +88,12 @@
|
||||
"spoofDialogYes": "Yes",
|
||||
"spoofDialogApplyTitle": "Apply settings?",
|
||||
"spoofDialogApplyContent": "Need to reconnect the app, ok?",
|
||||
"spoofDialogApplyWarning": "Your spoof will change immediately. But due to MAX specifics, you must re-login to the account for it to become visible",
|
||||
"spoofDialogReloginTitle": "Done!",
|
||||
"spoofDialogReloginContent": "Due to MAX specifics, your spoof is changed, but changes will be visible only after re-login.",
|
||||
"spoofDialogReloginWarning": "Re-login now?",
|
||||
"spoofDialogReloginDeny": "Later",
|
||||
"spoofDialogReloginConfirm": "Re-login now",
|
||||
"spoofDialogApplyDeny": "No",
|
||||
"spoofDialogApplyConfirm": "Ok!",
|
||||
"spoofErrorApplyFailed": "Failed to apply settings: {error}",
|
||||
|
||||
@@ -431,7 +431,7 @@ abstract class AppLocalizations {
|
||||
/// No description provided for @spoofDeviceTypeDescription.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Choose a device type for preset generation. Tapping \"Generate\" will only use presets of the selected type.'**
|
||||
/// **'This field is not changeable, to avoid token association issues'**
|
||||
String get spoofDeviceTypeDescription;
|
||||
|
||||
/// No description provided for @spoofDeviceTypeLabel.
|
||||
@@ -572,6 +572,42 @@ abstract class AppLocalizations {
|
||||
/// **'Need to reconnect the app, ok?'**
|
||||
String get spoofDialogApplyContent;
|
||||
|
||||
/// No description provided for @spoofDialogApplyWarning.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Your spoof will change immediately. But due to MAX specifics, you must re-login to the account for it to become visible'**
|
||||
String get spoofDialogApplyWarning;
|
||||
|
||||
/// No description provided for @spoofDialogReloginTitle.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Done!'**
|
||||
String get spoofDialogReloginTitle;
|
||||
|
||||
/// No description provided for @spoofDialogReloginContent.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Due to MAX specifics, your spoof is changed, but changes will be visible only after re-login.'**
|
||||
String get spoofDialogReloginContent;
|
||||
|
||||
/// No description provided for @spoofDialogReloginWarning.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Re-login now?'**
|
||||
String get spoofDialogReloginWarning;
|
||||
|
||||
/// No description provided for @spoofDialogReloginDeny.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Later'**
|
||||
String get spoofDialogReloginDeny;
|
||||
|
||||
/// No description provided for @spoofDialogReloginConfirm.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
/// **'Re-login now'**
|
||||
String get spoofDialogReloginConfirm;
|
||||
|
||||
/// No description provided for @spoofDialogApplyDeny.
|
||||
///
|
||||
/// In en, this message translates to:
|
||||
|
||||
@@ -183,7 +183,7 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get spoofDeviceTypeDescription =>
|
||||
'Choose a device type for preset generation. Tapping \"Generate\" will only use presets of the selected type.';
|
||||
'This field is not changeable, to avoid token association issues';
|
||||
|
||||
@override
|
||||
String get spoofDeviceTypeLabel => 'Device type';
|
||||
@@ -256,6 +256,26 @@ class AppLocalizationsEn extends AppLocalizations {
|
||||
@override
|
||||
String get spoofDialogApplyContent => 'Need to reconnect the app, ok?';
|
||||
|
||||
@override
|
||||
String get spoofDialogApplyWarning =>
|
||||
'Your spoof will change immediately. But due to MAX specifics, you must re-login to the account for it to become visible';
|
||||
|
||||
@override
|
||||
String get spoofDialogReloginTitle => 'Done!';
|
||||
|
||||
@override
|
||||
String get spoofDialogReloginContent =>
|
||||
'Due to MAX specifics, your spoof is changed, but changes will be visible only after re-login.';
|
||||
|
||||
@override
|
||||
String get spoofDialogReloginWarning => 'Re-login now?';
|
||||
|
||||
@override
|
||||
String get spoofDialogReloginDeny => 'Later';
|
||||
|
||||
@override
|
||||
String get spoofDialogReloginConfirm => 'Re-login now';
|
||||
|
||||
@override
|
||||
String get spoofDialogApplyDeny => 'No';
|
||||
|
||||
|
||||
@@ -185,7 +185,7 @@ class AppLocalizationsRu extends AppLocalizations {
|
||||
|
||||
@override
|
||||
String get spoofDeviceTypeDescription =>
|
||||
'Выберите тип устройства для генерации пресетов. При нажатии \"Сгенерировать\" будут использоваться только пресеты выбранного типа.';
|
||||
'Данное поле не изменяемое, во избежании проблем с ассоциацией токена';
|
||||
|
||||
@override
|
||||
String get spoofDeviceTypeLabel => 'Тип устройства';
|
||||
@@ -258,6 +258,26 @@ class AppLocalizationsRu extends AppLocalizations {
|
||||
@override
|
||||
String get spoofDialogApplyContent => 'Нужно перезайти в приложение, ок?';
|
||||
|
||||
@override
|
||||
String get spoofDialogApplyWarning =>
|
||||
'Ваш спуф изменится сразу. Но из-за особенностей МАХ, для того что-бы это стало заметно, вы должны перелогиниться в аккаунт';
|
||||
|
||||
@override
|
||||
String get spoofDialogReloginTitle => 'Готово!';
|
||||
|
||||
@override
|
||||
String get spoofDialogReloginContent =>
|
||||
'Из-за особенности МАХ, ваш спуф изменён, но видны изменения будут только при перезаходе в аккаунт.';
|
||||
|
||||
@override
|
||||
String get spoofDialogReloginWarning => 'Перезайти сейчас?';
|
||||
|
||||
@override
|
||||
String get spoofDialogReloginDeny => 'Позже';
|
||||
|
||||
@override
|
||||
String get spoofDialogReloginConfirm => 'Перелогиниться сейчас';
|
||||
|
||||
@override
|
||||
String get spoofDialogApplyDeny => 'Не';
|
||||
|
||||
|
||||
+7
-1
@@ -64,7 +64,7 @@
|
||||
"spoofMethodPartialDescription": "Рекомендуемый метод. Используются случайные данные, но ваш реальный часовой пояс и локаль для большей правдоподобности.",
|
||||
"spoofMethodFullDescription": "Все данные, включая часовой пояс и локаль, генерируются случайно. Использование этого метода на ваш страх и риск!",
|
||||
"spoofDeviceTypeTitle": "Тип устройства",
|
||||
"spoofDeviceTypeDescription": "Выберите тип устройства для генерации пресетов. При нажатии \"Сгенерировать\" будут использоваться только пресеты выбранного типа.",
|
||||
"spoofDeviceTypeDescription": "Данное поле не изменяемое, во избежании проблем с ассоциацией токена",
|
||||
"spoofDeviceTypeLabel": "Тип устройства",
|
||||
"spoofMainSectionTitle": "Основные данные",
|
||||
"spoofFieldDeviceName": "Имя устройства",
|
||||
@@ -88,6 +88,12 @@
|
||||
"spoofDialogYes": "Да",
|
||||
"spoofDialogApplyTitle": "Применить настройки?",
|
||||
"spoofDialogApplyContent": "Нужно перезайти в приложение, ок?",
|
||||
"spoofDialogApplyWarning": "Ваш спуф изменится сразу. Но из-за особенностей МАХ, для того что-бы это стало заметно, вы должны перелогиниться в аккаунт",
|
||||
"spoofDialogReloginTitle": "Готово!",
|
||||
"spoofDialogReloginContent": "Из-за особенности МАХ, ваш спуф изменён, но видны изменения будут только при перезаходе в аккаунт.",
|
||||
"spoofDialogReloginWarning": "Перезайти сейчас?",
|
||||
"spoofDialogReloginDeny": "Позже",
|
||||
"spoofDialogReloginConfirm": "Перелогиниться сейчас",
|
||||
"spoofDialogApplyDeny": "Не",
|
||||
"spoofDialogApplyConfirm": "Ок!",
|
||||
"spoofErrorApplyFailed": "Ошибка при применении настроек: {error}",
|
||||
|
||||
+13
-7
@@ -36,6 +36,7 @@ void main() async {
|
||||
await AppDatabase.init();
|
||||
await api.connect();
|
||||
final initialLocale = await _loadInitialLocale();
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final initialFpsOverlay = prefs.getBool('dev_fps_overlay') ?? false;
|
||||
runApp(
|
||||
@@ -70,8 +71,9 @@ class KometAppState extends State<KometApp> {
|
||||
|
||||
late Locale _locale;
|
||||
bool _isLoggingOut = false;
|
||||
late final ValueNotifier<bool> fpsOverlayEnabled =
|
||||
ValueNotifier(widget.initialFpsOverlay);
|
||||
late final ValueNotifier<bool> fpsOverlayEnabled = ValueNotifier(
|
||||
widget.initialFpsOverlay,
|
||||
);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -79,10 +81,14 @@ class KometAppState extends State<KometApp> {
|
||||
_locale = widget.initialLocale;
|
||||
|
||||
api.setReconnectCallback(() async {
|
||||
final accountId = await TokenStorage.getActiveAccountId();
|
||||
if (accountId != null) {
|
||||
await accountModule.login(accountId: accountId);
|
||||
}
|
||||
try {
|
||||
final accountId = await TokenStorage.getActiveAccountId();
|
||||
if (accountId != null &&
|
||||
await TokenStorage.readToken(accountId) != null) {
|
||||
final token = await TokenStorage.readToken(accountId);
|
||||
await accountModule.login(accountId: accountId, token: token);
|
||||
}
|
||||
} catch (_) {}
|
||||
});
|
||||
|
||||
api.sessionExpiredStream.listen((SessionExpiredException e) async {
|
||||
@@ -250,7 +256,7 @@ class _StartupScreenState extends State<_StartupScreen> {
|
||||
|
||||
Future<void> _tryAutoLogin() async {
|
||||
final accountId = await TokenStorage.getActiveAccountId();
|
||||
if (accountId == null) {
|
||||
if (accountId == null || await TokenStorage.readToken(accountId) == null) {
|
||||
_goToLogin();
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user