Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: retry login on foreground and update open setting #2326

Merged
merged 2 commits into from
Nov 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 63 additions & 17 deletions lib/screen/onboarding_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import 'package:autonomy_flutter/view/user_agent_utils.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:feralfile_app_theme/feral_file_app_theme.dart';
import 'package:flutter/material.dart';
import 'package:flutter_fgbg/flutter_fgbg.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:sentry/sentry.dart';
Expand All @@ -55,6 +56,8 @@ class _OnboardingPageState extends State<OnboardingPage>

final _passkeyService = injector.get<PasskeyService>();
final _userAccountChannel = injector.get<UserAccountChannel>();
bool? _isLoginSuccess;
late StreamSubscription<FGBGType> _fgbgSubscription;

final _onboardingLogo = Semantics(
label: 'onboarding_logo',
Expand All @@ -65,6 +68,32 @@ class _OnboardingPageState extends State<OnboardingPage>
),
);

@override
void initState() {
super.initState();
log.info('OnboardingPage initState');
// on foreground listener
_fgbgSubscription = FGBGEvents.stream.listen(_handleForeBackground);
}

void _handleForeBackground(FGBGType event) {
if (event == FGBGType.foreground) {
if (didRunSetup && _isLoginSuccess == false) {
// if setup is done and login is failed, try to login again
injector<NavigationService>().goBack(result: false);
unawaited(_fetchRuntimeCache());
}
} else {
log.info('App is in background');
}
}

@override
void dispose() {
unawaited(_fgbgSubscription.cancel());
super.dispose();
}

@override
void afterFirstLayout(BuildContext context) {
_timer = Timer(const Duration(seconds: 10), () {
Expand Down Expand Up @@ -138,7 +167,13 @@ class _OnboardingPageState extends State<OnboardingPage>

Future<void> _fetchRuntimeCache() async {
log.info('[_fetchRuntimeCache] start');
final isSuccess = await _loginProcess();
bool isSuccess = false;
try {
isSuccess = await _loginProcess();
} catch (e, s) {
ppupha marked this conversation as resolved.
Show resolved Hide resolved
log.info('Failed to login process: $e');
}
_isLoginSuccess = isSuccess;
if (!isSuccess) {
log.info('Login process failed');
unawaited(Sentry.captureMessage('Login process failed'));
Expand Down Expand Up @@ -171,15 +206,17 @@ class _OnboardingPageState extends State<OnboardingPage>
if (!doesOSSupport) {
log.info('OS does not support passkey');
_passkeyService.isShowingLoginDialog.value = true;
await _showBackupRecoveryPhraseDialog();
_passkeyService.isShowingLoginDialog.value = false;
unawaited(_showBackupRecoveryPhraseDialog().then((_) {
_passkeyService.isShowingLoginDialog.value = false;
}));
return false;
}
if (!canAuthenticate) {
log.info('OS supports passkey but cannot authenticate');
_passkeyService.isShowingLoginDialog.value = true;
await _showAuthenticationUpdateRequired();
_passkeyService.isShowingLoginDialog.value = false;
unawaited(_showAuthenticationUpdateRequired().then((_) {
_passkeyService.isShowingLoginDialog.value = false;
}));
return false;
}
return false;
Expand Down Expand Up @@ -218,18 +255,27 @@ class _OnboardingPageState extends State<OnboardingPage>

Future<void> _loginAndMigrate() async {
log.info('Login and migrate');
await injector<AccountService>().migrateAccount(() async {
try {
log.info('[_loginAndMigrate] create JWT token');
final localResponse = await _passkeyService.logInInitiate();
await _passkeyService.logInFinalize(localResponse);
log.info('[_loginAndMigrate] create JWT token done');
} catch (e, s) {
log.info('Failed to create login JWT: $e');
unawaited(Sentry.captureException(e, stackTrace: s));
rethrow;
}
});
_isLoginSuccess = null;
try {
await injector<AccountService>().migrateAccount(() async {
try {
log.info('[_loginAndMigrate] create JWT token');
final localResponse = await _passkeyService.logInInitiate();
await _passkeyService.logInFinalize(localResponse);
log.info('[_loginAndMigrate] create JWT token done');
} catch (e, s) {
log.info('Failed to create login JWT: $e');
unawaited(Sentry.captureException(e, stackTrace: s));
rethrow;
}
});
_isLoginSuccess = true;
} catch (e, s) {
_isLoginSuccess = false;
log.info('Failed to migrate account: $e');
unawaited(Sentry.captureException(e, stackTrace: s));
rethrow;
}
log.info('Login and migrate done');
}

Expand Down
16 changes: 13 additions & 3 deletions lib/service/navigation_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ import 'package:flutter_vibrate/flutter_vibrate.dart';
import 'package:libauk_dart/libauk_dart.dart';
import 'package:nft_collection/database/nft_collection_database.dart';
import 'package:nft_collection/models/asset_token.dart'; // ignore_for_file: implementation_imports
import 'package:open_settings_plus/open_settings_plus.dart';
import 'package:overlay_support/src/overlay_state_finder.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:sentry/sentry.dart';
import 'package:url_launcher/url_launcher_string.dart';

Expand Down Expand Up @@ -180,6 +180,16 @@ class NavigationService {
}
}

Future<void> openAuthenticationSettings() async {
if (Platform.isAndroid) {
final settings = OpenSettingsPlus.shared! as OpenSettingsPlusAndroid;
await settings.biometricEnroll();
} else {
final settings = OpenSettingsPlus.shared! as OpenSettingsPlusIOS;
await settings.faceIDAndPasscode();
}
}

Future<void> showAppLoadError() async {
if (navigatorKey.currentState?.mounted == true &&
navigatorKey.currentContext != null) {
Expand Down Expand Up @@ -1186,8 +1196,8 @@ class NavigationService {
children: [
PrimaryButton(
text: 'go_to_settings'.tr(),
onTap: () async {
await openAppSettings();
onTap: () {
openAuthenticationSettings();
},
),
const SizedBox(height: 20),
Expand Down
5 changes: 4 additions & 1 deletion lib/service/passkey_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,10 @@ class PasskeyServiceImpl implements PasskeyService {

@override
Future<bool> canAuthenticate() async =>
await _passkeyAuthenticator.canAuthenticate();
Platform.isAndroid ? await _passkeyAuthenticator.canAuthenticate() : true;

// passkey available always return true for iOS
// if no verification method is available, the user will be prompted to set up passcode or faceID
ppupha marked this conversation as resolved.
Show resolved Hide resolved

@override
Future<AuthenticateResponseType> logInInitiate() async {
Expand Down
58 changes: 37 additions & 21 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -365,10 +365,10 @@ packages:
dependency: "direct main"
description:
name: collection
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev"
source: hosted
version: "1.19.0"
version: "1.18.0"
confetti:
dependency: "direct main"
description:
Expand Down Expand Up @@ -1691,18 +1691,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
url: "https://pub.dev"
source: hosted
version: "10.0.7"
version: "10.0.5"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
url: "https://pub.dev"
source: hosted
version: "3.0.8"
version: "3.0.5"
leak_tracker_testing:
dependency: transitive
description:
Expand Down Expand Up @@ -1864,6 +1864,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.4"
mixpanel_flutter:
dependency: "direct main"
description:
name: mixpanel_flutter
sha256: c1e35c54d8cfc1c50d35d2e8cc11416295efc45bb6dcaa88aec8f82219274833
url: "https://pub.dev"
source: hosted
version: "2.3.3"
mockito:
dependency: "direct dev"
description:
Expand Down Expand Up @@ -1969,6 +1977,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.2"
open_settings_plus:
dependency: "direct main"
description:
name: open_settings_plus
sha256: "5f813700e62bc77db830e0225e09e77c6573c67784a4e7b00483f3a16341c081"
url: "https://pub.dev"
source: hosted
version: "0.3.3"
openapi_generator_annotations:
dependency: transitive
description:
Expand Down Expand Up @@ -2549,7 +2565,7 @@ packages:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
version: "0.0.99"
slidable_button:
dependency: "direct main"
description:
Expand Down Expand Up @@ -2666,10 +2682,10 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://pub.dev"
source: hosted
version: "1.12.0"
version: "1.11.1"
stream_channel:
dependency: transitive
description:
Expand All @@ -2690,10 +2706,10 @@ packages:
dependency: transitive
description:
name: string_scanner
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.2.0"
strings:
dependency: transitive
description:
Expand Down Expand Up @@ -2746,26 +2762,26 @@ packages:
dependency: "direct dev"
description:
name: test
sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f"
sha256: "7ee44229615f8f642b68120165ae4c2a75fe77ae2065b1e55ae4711f6cf0899e"
url: "https://pub.dev"
source: hosted
version: "1.25.8"
version: "1.25.7"
test_api:
dependency: transitive
description:
name: test_api
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
url: "https://pub.dev"
source: hosted
version: "0.7.3"
version: "0.7.2"
test_core:
dependency: transitive
description:
name: test_core
sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d"
sha256: "55ea5a652e38a1dfb32943a7973f3681a60f872f8c3a05a14664ad54ef9c6696"
url: "https://pub.dev"
source: hosted
version: "0.6.5"
version: "0.6.4"
tezart:
dependency: "direct main"
description:
Expand Down Expand Up @@ -2995,10 +3011,10 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
url: "https://pub.dev"
source: hosted
version: "14.3.0"
version: "14.2.5"
wakelock_plus:
dependency: "direct main"
description:
Expand Down Expand Up @@ -3067,10 +3083,10 @@ packages:
dependency: transitive
description:
name: webdriver
sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8"
sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e"
url: "https://pub.dev"
source: hosted
version: "3.0.4"
version: "3.0.3"
webkit_inspection_protocol:
dependency: transitive
description:
Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ dependencies:
mixpanel_flutter: ^2.0.0
onesignal_flutter: ^5.2.6
open_settings: ^2.0.2
open_settings_plus: ^0.3.3
overlay_support: ^2.0.0
package_info_plus: ^8.0.3
page_transition: ^2.0.5
Expand Down
Loading