Vaani/lib/features/onboarding/view/user_login_with_open_id.dart
Dr.Blank 25be7fda03
fix: keyboard not showing when adding new user (#79)
* feat: add fadeSlideTransitionBuilder for smoother transitions in user login

* fix: reuse onboarding components on server manager page

* fix: gaining focus rebuilt the widget

using memoized fixes this issue
2025-04-23 15:00:01 +05:30

121 lines
3.9 KiB
Dart

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:shelfsdk/audiobookshelf_api.dart';
import 'package:vaani/api/api_provider.dart';
import 'package:vaani/features/onboarding/providers/oauth_provider.dart';
import 'package:vaani/features/onboarding/view/user_login_with_password.dart';
import 'package:vaani/main.dart';
import 'package:vaani/models/error_response.dart';
import 'package:vaani/router/router.dart';
import 'package:vaani/settings/constants.dart';
import 'package:vaani/settings/models/models.dart' as model;
import 'package:vaani/shared/extensions/obfuscation.dart';
import 'package:vaani/shared/utils.dart';
class UserLoginWithOpenID extends HookConsumerWidget {
UserLoginWithOpenID({
super.key,
required this.server,
required this.addServer,
this.openIDButtonText,
this.onSuccess,
});
final Uri server;
final model.AudiobookShelfServer Function() addServer;
final String? openIDButtonText;
final responseErrorHandler = ErrorResponseHandler(name: 'OpenID');
final Function(model.AuthenticatedUser)? onSuccess;
@override
Widget build(BuildContext context, WidgetRef ref) {
final serverStatus = ref.watch(serverStatusProvider(server));
void openIDLoginFlow() async {
appLogger.fine('Clicked Login with OpenID');
final api = ref.read(audiobookshelfApiProvider(server));
final (verifier, challenge) = generateVerifierAndChallenge();
appLogger.fine('Generated verifier: $verifier\nchallenge: $challenge');
final appRedirectUri =
'${AppMetadata.appScheme}://${Routes.openIDCallback.fullPath.substring(1)}';
final (openIDLoginEndpoint, authCookie) = await api.server.oauth2Request(
clientId: AppMetadata.appName,
codeChallenge: challenge,
// redirectUri: Uri(
// scheme: AppMetadata.appScheme,
// host: Routes.openIDCallback.path.substring(1),
// ).toString(),
redirectUri: appRedirectUri,
responseErrorHandler: responseErrorHandler.storeError,
);
if (openIDLoginEndpoint == null) {
if (responseErrorHandler.response.statusCode == 400 &&
responseErrorHandler.response.body
.toLowerCase()
.contains(RegExp(r'invalid.*redirect.*uri'))) {
// show error
handleServerError(
context,
responseErrorHandler,
title: 'Failed to get OpenID login endpoint\n',
body:
'Please check that the redirect URI: "$appRedirectUri" is registered with the server.',
outLink: server.replace(path: '${Routes.settings.fullPath}/auth'),
outLinkText: 'Server settings',
);
return;
}
// show error
handleServerError(
context,
responseErrorHandler,
title: 'Failed to get OpenID login endpoint',
);
return;
}
// extract the state parameter
final oauthState = openIDLoginEndpoint.queryParameters['state'];
if (oauthState == null) {
handleServerError(
context,
responseErrorHandler,
title: 'Failed to get OpenID login endpoint',
body: 'No state parameter found in the response',
);
return;
}
appLogger.fine(
'Got OpenID login endpoint: ${openIDLoginEndpoint.obfuscate()}',
);
// add the flow to the provider
ref.read(oauthFlowsProvider.notifier).addFlow(
oauthState,
verifier: verifier,
serverUri: server,
cookie: Cookie.fromSetCookieValue(authCookie!),
);
await handleLaunchUrl(
openIDLoginEndpoint,
);
}
return Column(
children: [
ElevatedButton(
onPressed: openIDLoginFlow,
child: Text(openIDButtonText ?? 'Login with OpenID'),
),
],
);
}
}