114 lines
3.5 KiB
Dart
114 lines
3.5 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
|
|
import '../../../common/router/app_router.dart';
|
|
import 'auth_controller.dart';
|
|
import 'one_key_login_service.dart';
|
|
|
|
abstract final class LoginLauncher {
|
|
static final OneKeyLoginService _service = OneKeyLoginService();
|
|
static bool _starting = false;
|
|
|
|
static Future<void> start(
|
|
BuildContext context,
|
|
WidgetRef ref, {
|
|
String? next,
|
|
}) async {
|
|
if (_starting) return;
|
|
_starting = true;
|
|
|
|
var loadingVisible = false;
|
|
|
|
void showLoading() {
|
|
if (loadingVisible || !context.mounted) return;
|
|
loadingVisible = true;
|
|
unawaited(
|
|
showDialog<void>(
|
|
context: context,
|
|
useRootNavigator: true,
|
|
barrierDismissible: false,
|
|
builder: (_) => const PopScope(
|
|
canPop: false,
|
|
child: Center(child: CircularProgressIndicator()),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
void dismissLoading() {
|
|
if (!loadingVisible || !context.mounted) return;
|
|
loadingVisible = false;
|
|
Navigator.of(context, rootNavigator: true).pop();
|
|
}
|
|
|
|
try {
|
|
final observer = _OneKeyLoginLifecycleObserver(_service);
|
|
var observerAdded = false;
|
|
late final OneKeyLoginOutcome outcome;
|
|
try {
|
|
WidgetsBinding.instance.addObserver(observer);
|
|
observerAdded = true;
|
|
// Carrier-auth initialization only begins after this explicit login
|
|
// action. Keep the loading indicator visible while the native SDK
|
|
// determines whether one-key login can be launched.
|
|
showLoading();
|
|
outcome = await _service.start(
|
|
context: context,
|
|
verifyToken: ref.read(authProvider.notifier).verifyOneKeyLogin,
|
|
// The native carrier page follows the device, while linked H5 pages
|
|
// retain the appearance selected inside the app.
|
|
appIsDark: Theme.of(context).brightness == Brightness.dark,
|
|
nativeIsDark:
|
|
MediaQuery.platformBrightnessOf(context) == Brightness.dark,
|
|
onNativeRequestDispatched: dismissLoading,
|
|
onAuthPageOpened: dismissLoading,
|
|
);
|
|
} finally {
|
|
dismissLoading();
|
|
if (observerAdded) WidgetsBinding.instance.removeObserver(observer);
|
|
}
|
|
|
|
if (!context.mounted) return;
|
|
switch (outcome) {
|
|
case OneKeyLoginOutcome.success:
|
|
if (next != null && next.isNotEmpty) GoRouter.of(context).go(next);
|
|
return;
|
|
case OneKeyLoginOutcome.cancelled:
|
|
case OneKeyLoginOutcome.busy:
|
|
return;
|
|
case OneKeyLoginOutcome.fallback:
|
|
case OneKeyLoginOutcome.unsupported:
|
|
await openSmsLogin(context, next: next);
|
|
}
|
|
} finally {
|
|
_starting = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<void> openSmsLogin(
|
|
BuildContext context, {
|
|
String? next,
|
|
Future<void> Function()? onReturn,
|
|
}) async {
|
|
if (!context.mounted) return;
|
|
if (GoRouterState.of(context).matchedLocation == AppRoutes.login) return;
|
|
final location = next == null || next.isEmpty
|
|
? AppRoutes.login
|
|
: '${AppRoutes.login}?next=${Uri.encodeComponent(next)}';
|
|
await GoRouter.of(context).push(location);
|
|
if (context.mounted) await onReturn?.call();
|
|
}
|
|
|
|
class _OneKeyLoginLifecycleObserver with WidgetsBindingObserver {
|
|
_OneKeyLoginLifecycleObserver(this.service);
|
|
final OneKeyLoginService service;
|
|
@override
|
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
|
if (state == AppLifecycleState.resumed) service.onAppResumed();
|
|
}
|
|
}
|