💄 Better multi-factor authenticate callback experience

 Support custom app protocol solink://
This commit is contained in:
2024-06-29 18:09:56 +08:00
parent 6b0f644353
commit fffad00f00
14 changed files with 235 additions and 77 deletions

View File

@ -2,6 +2,7 @@ import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_acrylic/flutter_acrylic.dart';
import 'package:get/get.dart';
import 'package:protocol_handler/protocol_handler.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:solian/exts.dart';
import 'package:solian/firebase_options.dart';
@ -17,6 +18,7 @@ import 'package:solian/providers/content/realm.dart';
import 'package:solian/providers/friend.dart';
import 'package:solian/providers/account_status.dart';
import 'package:solian/router.dart';
import 'package:solian/shells/listener_shell.dart';
import 'package:solian/theme.dart';
import 'package:solian/translations.dart';
@ -31,6 +33,8 @@ void main() async {
appRunner: () async {
WidgetsFlutterBinding.ensureInitialized();
await protocolHandler.register('solink');
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
@ -101,8 +105,10 @@ class SolianApp extends StatelessWidget {
});
},
builder: (context, child) {
return ScaffoldMessenger(
child: child ?? Container(),
return ListenerShell(
child: ScaffoldMessenger(
child: child ?? Container(),
),
);
},
);

View File

@ -41,8 +41,10 @@ class _SignInPopupState extends State<SignInPopup> {
TextButton(
child: Text('next'.tr),
onPressed: () {
const redirect = 'solink://auth?status=done';
launchUrlString(
'${ServiceFinder.services['passport']}/mfa?close=yes&ticketId=${e.ticketId}',
'${ServiceFinder.services['passport']}/mfa?redirect_uri=$redirect&ticketId=${e.ticketId}',
mode: LaunchMode.inAppWebView,
);
Navigator.pop(context);
},

View File

@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
import 'package:protocol_handler/protocol_handler.dart';
import 'package:url_launcher/url_launcher.dart';
class ListenerShell extends StatefulWidget {
final Widget child;
const ListenerShell({super.key, required this.child});
@override
State<ListenerShell> createState() => _ListenerShellState();
}
class _ListenerShellState extends State<ListenerShell> with ProtocolListener {
@override
void initState() {
protocolHandler.addListener(this);
super.initState();
}
@override
void dispose() {
protocolHandler.removeListener(this);
super.dispose();
}
@override
Widget build(BuildContext context) {
return widget.child;
}
@override
void onProtocolUrlReceived(String url) {
final uri = url.replaceFirst('solink://', '');
if (uri == 'auth?status=done') {
closeInAppWebView();
}
}
}