import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_login_yandex/flutter_login_yandex.dart'; import 'package:eatvio_app/core/app_router.dart'; import 'package:eatvio_app/core/env_config.dart'; import 'package:vk_id/vk_id.dart'; import 'package:webview_flutter/webview_flutter.dart'; class VkAuthResult { VkAuthResult({required this.accessToken, this.refreshToken, this.userId, this.firstName, this.lastName, this.email, this.phone, this.gender, this.birthDate}); final String accessToken; final String? refreshToken; final String? userId; final String? firstName; final String? lastName; final String? email; final String? phone; final String? gender; final String? birthDate; } class SocialAuthFacade { static Future signInWithVk({required BuildContext context}) async { final result = await signInWithVkAndFetchProfile(context: context); return result?.accessToken; } static Future signInWithVkAndFetchProfile({required BuildContext context}) async { final clientIdStr = EnvConfig.vkClientId.trim(); if (clientIdStr.isEmpty) { return null; } try { dynamic controller = VkIDController(clID: int.parse(clientIdStr)); final authUri = controller.generateAuthorizeLinkWithCodeVerifier(); String authUrl; if (authUri is MapEntry) { authUrl = authUri.value.toString(); } else { authUrl = authUri.toString(); } final redirectScheme = 'vk$clientIdStr://'; final redirectParams = await _presentOAuthWebView(context: context, initialUrl: authUrl, redirectSchemePrefix: redirectScheme); if (redirectParams == null) { return null; } final code = redirectParams['code']; final deviceId = redirectParams['device_id']; if (code == null || deviceId == null) { return null; } return VkAuthResult(accessToken: code); } catch (e) { return null; } } static Future signInWithOk() async { final context = AppRouter.navigatorKey.currentContext; if (context == null) return null; return _signInWithVkIdProvider(context: context, provider: 'ok'); } static Future signInWithMailRu() async { final context = AppRouter.navigatorKey.currentContext; if (context == null) return null; return _signInWithVkIdProvider(context: context, provider: 'mail'); } static Future signInWithYandex() async { final clientId = EnvConfig.yandexClientId.trim(); final redirectUri = EnvConfig.yandexRedirectUri.trim(); if (clientId.isEmpty || redirectUri.isEmpty) { return null; } try { final context = AppRouter.navigatorKey.currentContext; if (context == null) return null; final authorizeUrl = Uri.https('oauth.yandex.ru', '/authorize', { 'response_type': 'token', 'client_id': clientId, 'redirect_uri': redirectUri, 'force_confirm': 'yes', }).toString(); final redirectSchemePrefix = redirectUri; final params = await _presentOAuthWebView(context: context, initialUrl: authorizeUrl, redirectSchemePrefix: redirectSchemePrefix); if (params == null) return null; final token = params['access_token']; if (token != null && token.isNotEmpty) { return token; } final code = params['code']; if (code != null && code.isNotEmpty) { return code; } return null; } catch (e) { try { final plugin = FlutterLoginYandex(); final response = await plugin.signIn(); final token = (response is Map) ? response['token'] as String? : null; return (token != null && token.isNotEmpty) ? token : null; } catch (_) { return null; } } } static Future _signInWithVkIdProvider({required BuildContext context, required String provider}) async { final clientIdStr = EnvConfig.vkClientId.trim(); if (clientIdStr.isEmpty) { return null; } try { dynamic controller = VkIDController(clID: int.parse(clientIdStr)); dynamic authUri; try { authUri = controller.generateAuthorizeLinkWithCodeVerifier(provider: provider); } catch (e) { try { authUri = controller.generateAuthorizeLinkWithCodeVerifier(provider: null); } catch (e2) { authUri = controller.generateAuthorizeLinkWithCodeVerifier(); } } // Extract URL from MapEntry String authUrl; if (authUri is MapEntry) { authUrl = authUri.value.toString(); } else { authUrl = authUri.toString(); } final redirectScheme = 'vk$clientIdStr://'; final redirectParams = await _presentOAuthWebView(context: context, initialUrl: authUrl, redirectSchemePrefix: redirectScheme); if (redirectParams == null) return null; final code = redirectParams['code']; final deviceId = redirectParams['device_id']; if (code == null || deviceId == null) return null; return code; } catch (e) { return null; } } static Future?> _presentOAuthWebView({ required BuildContext context, required String initialUrl, required String redirectSchemePrefix, }) async { final controller = WebViewController() ..setJavaScriptMode(JavaScriptMode.unrestricted) ..setNavigationDelegate( NavigationDelegate( onNavigationRequest: (request) { final url = request.url; if (url.startsWith(redirectSchemePrefix)) { final uri = Uri.parse(url); final params = {}..addAll(uri.queryParameters); if (uri.fragment.isNotEmpty) { final fragPairs = uri.fragment.split('&'); for (final pair in fragPairs) { final eq = pair.indexOf('='); if (eq > 0 && eq < pair.length - 1) { final key = Uri.decodeComponent(pair.substring(0, eq)); final value = Uri.decodeComponent(pair.substring(eq + 1)); params[key] = value; } } } Navigator.of(context, rootNavigator: true).pop(params); return NavigationDecision.prevent; } return NavigationDecision.navigate; }, onPageStarted: (url) { }, onPageFinished: (url) { }, onWebResourceError: (error) { }, ), ); try { await controller.loadRequest(Uri.parse(initialUrl)); } catch (e) { return null; } return showDialog>( context: context, barrierDismissible: false, builder: (_) { const borderRadius = BorderRadius.all(Radius.circular(16)); return Dialog( insetPadding: const EdgeInsets.all(16), shape: const RoundedRectangleBorder(borderRadius: borderRadius), elevation: 0, child: ClipRRect( borderRadius: borderRadius, child: SizedBox(height: 560, child: WebViewWidget(controller: controller)), ), ); }, ); } }