diff --git a/client_mobile/android/settings.gradle b/client_mobile/android/settings.gradle index 536165d..74bd010 100644 --- a/client_mobile/android/settings.gradle +++ b/client_mobile/android/settings.gradle @@ -18,8 +18,8 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "7.3.0" apply false - id "org.jetbrains.kotlin.android" version "1.7.10" apply false + id "com.android.application" version "7.3.1" apply false + id "org.jetbrains.kotlin.android" version "2.1.0" apply false } include ":app" diff --git a/client_mobile/assets/images/microsoft_logo.png b/client_mobile/assets/images/microsoft_logo.png new file mode 100644 index 0000000..3e62d6d Binary files /dev/null and b/client_mobile/assets/images/microsoft_logo.png differ diff --git a/client_mobile/lib/features/auth/login.dart b/client_mobile/lib/features/auth/login.dart index 2b8f996..26982eb 100644 --- a/client_mobile/lib/features/auth/login.dart +++ b/client_mobile/lib/features/auth/login.dart @@ -1,4 +1,5 @@ // import 'dart:io'; +import 'package:client_mobile/services/microsoft/microsoft_auth_service.dart'; import 'package:client_mobile/widgets/button.dart'; import 'package:client_mobile/widgets/clickable_text.dart'; import 'package:client_mobile/widgets/form_field.dart'; @@ -6,15 +7,8 @@ import 'package:client_mobile/widgets/sign_in_button.dart'; import 'package:client_mobile/widgets/simple_text.dart'; import 'package:flutter/material.dart'; import 'package:flutter_appauth/flutter_appauth.dart'; -import 'package:flutter_web_auth/flutter_web_auth.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:go_router/go_router.dart'; -import 'package:oauth2/oauth2.dart' as oauth2; -// import 'package:http/http.dart' as http; import 'package:flutter_dotenv/flutter_dotenv.dart'; -// import 'package:oauth2_client/access_token_response.dart'; -// import 'package:oauth2_client/authorization_response.dart'; -// import 'package:oauth2_client/spotify_oauth2_client.dart'; class LoginPage extends StatefulWidget { @override @@ -23,190 +17,64 @@ class LoginPage extends StatefulWidget { class _LoginPageState extends State { final String callbackUrlScheme = 'my.area.app'; - String get redirectUrlMobile => '$callbackUrlScheme://callback'; + String get spotifyRedirectUrlMobile => '$callbackUrlScheme://callback'; final String clientId = dotenv.env["VITE_SPOTIFY_CLIENT_ID"] ?? ""; - final appAuth = FlutterAppAuth(); - final String clientSecret = dotenv.env["VITE_SPOTIFY_CLIENT_SECRET"] ?? ""; - final String issuer = "https://accounts.spotify.com/"; - final Uri authorizationEndpoint = - Uri.parse('https://accounts.spotify.com/authorize'); - final Uri tokenEndpoint = Uri.parse('https://accounts.spotify.com/api/token'); - final String redirectUrlWeb = "https://localhost:8081/auth/spotify/callback"; - final Uri redirectUri = - Uri.parse('https://localhost:8081/auth/spotify/callback'); - oauth2.Client? client; - - Future authenticateWithSpotify() async { - try { - final String spotifyUrl = 'https://accounts.spotify.com/authorize' - '&client_id=$clientId' - '&redirect_uri=$redirectUrlMobile'; - - print("Authentification en cours ..."); - final result = await FlutterWebAuth.authenticate( - url: spotifyUrl, - callbackUrlScheme: callbackUrlScheme, - ); - - print("voici le résultat : ${result}"); - } catch (e) { - print("erreur d'authentification : ${e}"); - } - } - - Future authenticateWithSpotifyOld() async { - try { - // print("client id : ${clientId}"); - // AccessTokenResponse? accessToken; - // SpotifyOAuth2Client client = SpotifyOAuth2Client( - // redirectUri: redirectUrlMobile, - // customUriScheme: "my.area.app" - // ); - - // var authResp = - // await client.requestAuthorization(clientId: clientId, customParams: { - // // 'show_dialog': 'true' - // }, scopes: [ - // 'user-read-private', - // 'user-read-playback-state', - // 'user-modify-playback-state', - // 'user-read-currently-playing', - // 'user-read-email' - // ]); - // var authCode = authResp.code; - - // print("auth code : ${authCode}"); - - final authorizationTokenRequest = AuthorizationTokenRequest( - clientId, redirectUrlMobile, - issuer: issuer, - clientSecret: clientSecret, - scopes: ["openid", "profile", "email", "offline_access"], - additionalParameters: {'show_dialog': 'true'}); - - final result = - await appAuth.authorizeAndExchangeCode(authorizationTokenRequest); - - print("--------------------------------"); - print(""); - print(""); - print("Le code échangé est le suivant : ${result}"); - print(""); - print(""); - print("--------------------------------"); - - return; - // Start a small HTTP server to capture the callback - // final server = await HttpServer.bind(InternetAddress.loopbackIPv4, 8080); - // print("Listening on ${server.address}:${server.port}"); - - // // Build the OAuth2 flow - // final grant = oauth2.AuthorizationCodeGrant( - // clientId, - // authorizationEndpoint, - // tokenEndpoint, - // secret: clientSecret, - // httpClient: http.Client(), - // ); - - // // Generate the authorization URL - // final authorizationUrl = grant.getAuthorizationUrl(redirectUri, scopes: [ - // 'user-read-email', - // 'user-read-private', - // ]); - - // // Open the browser for user login - // print('Opening browser: $authorizationUrl'); - // await Process.run('open', [authorizationUrl.toString()]); - - // // Wait for the callback - // final request = await server.first; - - // // Validate and close the server - // final queryParameters = request.uri.queryParameters; - // final code = queryParameters['code']; - // final state = queryParameters['state']; - // request.response - // ..statusCode = 200 - // ..headers.set('Content-Type', ContentType.html.mimeType) - // ..write('You can now close this page.') - // ..close(); - // await server.close(); - - // // Exchange the authorization code for tokens - // if (code != null) { - // client = await grant.handleAuthorizationCode(code); - // setState(() {}); - // print( - // 'Authenticated successfully! Access token: ${client?.credentials.accessToken}'); - // } - } catch (e) { - print('Authentication failed: $e'); - } - } + final appAuth = const FlutterAppAuth(); @override Widget build(BuildContext context) { return Scaffold( body: Center( - child: client == null - ? Container( - padding: const EdgeInsets.all(20), - child: SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SimpleText( - "Email", - bold: true, - ), - const AreaFormField(label: "Value"), - const SizedBox(height: 50), - const SimpleText("Password", bold: true), - const AreaFormField(label: "Value"), - const SizedBox(height: 15), - Align( - alignment: Alignment.center, - child: AreaButton( - label: "Login", - onPressed: () {}, - color: Colors.black, - ), - ), - const SizedBox(height: 30), - Align( - alignment: Alignment.center, - child: SignInButton( - onPressed: () { - authenticateWithSpotifyOld(); - }, - label: "Sign in with Spotify", - icon: const FaIcon( - size: 34, - FontAwesomeIcons.spotify, - color: Colors.green, - ), - ), - ), - const SizedBox(height: 5), - Align( - alignment: Alignment.center, - child: SmallClickableText( - "I don't have an account", - onPressed: () { - context.push("/register"); - }, - ), - ) - ], + child: Container( + padding: const EdgeInsets.all(20), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SimpleText( + "Email", + bold: true, + ), + const AreaFormField(label: "Value"), + const SizedBox(height: 50), + const SimpleText("Password", bold: true), + const AreaFormField(label: "Value"), + const SizedBox(height: 15), + AreaButton( + label: "Login", + onPressed: () {}, + color: Colors.black, + ), + const SizedBox(height: 30), + Align( + alignment: Alignment.center, + child: SignInButton( + onPressed: () { + MicrosoftAuthService.auth(context); + }, + label: "Sign in with Microsoft", + image: Image.asset( + "assets/images/microsoft_logo.png", + width: 40, + height: 30, ), ), + ), + const SizedBox(height: 5), + Align( + alignment: Alignment.center, + child: SmallClickableText( + "I don't have an account", + onPressed: () { + context.push("/register"); + }, + ), ) - : Text( - 'Authenticated! Access token: ${client?.credentials.accessToken}'), - ), + ], + ), + ), + )), ); } } diff --git a/client_mobile/lib/features/auth/register.dart b/client_mobile/lib/features/auth/register.dart index 86ea991..af46783 100644 --- a/client_mobile/lib/features/auth/register.dart +++ b/client_mobile/lib/features/auth/register.dart @@ -1,4 +1,5 @@ // import 'dart:io'; +import 'package:client_mobile/services/microsoft/microsoft_auth_service.dart'; import 'package:client_mobile/widgets/button.dart'; import 'package:client_mobile/widgets/clickable_text.dart'; import 'package:client_mobile/widgets/form_field.dart'; @@ -6,15 +7,8 @@ import 'package:client_mobile/widgets/sign_in_button.dart'; import 'package:client_mobile/widgets/simple_text.dart'; import 'package:flutter/material.dart'; import 'package:flutter_appauth/flutter_appauth.dart'; -// import 'package:flutter_web_auth/flutter_web_auth.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:go_router/go_router.dart'; -import 'package:oauth2/oauth2.dart' as oauth2; -// import 'package:http/http.dart' as http; import 'package:flutter_dotenv/flutter_dotenv.dart'; -// import 'package:oauth2_client/access_token_response.dart'; -// import 'package:oauth2_client/authorization_response.dart'; -// import 'package:oauth2_client/spotify_oauth2_client.dart'; class RegisterPage extends StatefulWidget { @override @@ -23,110 +17,71 @@ class RegisterPage extends StatefulWidget { class _RegisterPageState extends State { final String callbackUrlScheme = 'my.area.app'; - String get redirectUrlMobile => '$callbackUrlScheme://callback'; + String get spotifyRedirectUrlMobile => '$callbackUrlScheme://callback'; final String clientId = dotenv.env["VITE_SPOTIFY_CLIENT_ID"] ?? ""; - final appAuth = FlutterAppAuth(); - final String clientSecret = dotenv.env["VITE_SPOTIFY_CLIENT_SECRET"] ?? ""; - final String issuer = "https://accounts.spotify.com/"; - final Uri authorizationEndpoint = - Uri.parse('https://accounts.spotify.com/authorize'); - final Uri tokenEndpoint = Uri.parse('https://accounts.spotify.com/api/token'); - final String redirectUrlWeb = "https://localhost:8081/auth/spotify/callback"; - final Uri redirectUri = - Uri.parse('https://localhost:8081/auth/spotify/callback'); - oauth2.Client? client; - - Future authenticateWithSpotifyOld() async { - try { - final authorizationTokenRequest = AuthorizationTokenRequest( - clientId, redirectUrlMobile, - issuer: issuer, - clientSecret: clientSecret, - scopes: ["openid", "profile", "email", "offline_access"], - additionalParameters: {'show_dialog': 'true'}); - - final result = - await appAuth.authorizeAndExchangeCode(authorizationTokenRequest); - - print("--------------------------------"); - print(""); - print(""); - print("Le code échangé est le suivant : ${result}"); - print(""); - print(""); - print("--------------------------------"); - - return; - } catch (e) { - print('Authentication failed: $e'); - } - } + final appAuth = const FlutterAppAuth(); @override Widget build(BuildContext context) { return Scaffold( body: Center( - child: client == null - ? Container( - padding: const EdgeInsets.all(20), - child: SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SimpleText( - "Username", - bold: true, - ), - const AreaFormField(label: "Value"), - const SizedBox(height: 25), - const SimpleText("Password", bold: true), - const AreaFormField(label: "Value"), - const SizedBox(height: 15), - const SimpleText("Confirm password", bold: true), - const AreaFormField(label: "Value"), - const SizedBox(height: 15), - Align( - alignment: Alignment.center, - child: AreaButton( - label: "Register", - onPressed: () {}, - color: Colors.black, - ), - ), - const SizedBox(height: 30), - Align( - alignment: Alignment.center, - child: SignInButton( - onPressed: () { - authenticateWithSpotifyOld(); - }, - label: "Sign in with Spotify", - icon: const FaIcon( - size: 34, - FontAwesomeIcons.spotify, - color: Colors.green, - ), - ), - ), - const SizedBox(height: 5), - Align( - alignment: Alignment.center, - child: SmallClickableText( - "I already have an account", - onPressed: () { - context.pop(); - }, - ), - ) - ], + child: Container( + padding: const EdgeInsets.all(20), + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SimpleText( + "Username", + bold: true, + ), + const AreaFormField(label: "Value"), + const SizedBox(height: 25), + const SimpleText("Password", bold: true), + const AreaFormField(label: "Value"), + const SizedBox(height: 15), + const SimpleText("Confirm password", bold: true), + const AreaFormField(label: "Value"), + const SizedBox(height: 15), + Align( + alignment: Alignment.center, + child: AreaButton( + label: "Register", + onPressed: () {}, + color: Colors.black, + ), + ), + const SizedBox(height: 30), + Align( + alignment: Alignment.center, + child: SignInButton( + onPressed: () { + MicrosoftAuthService.auth(context); + }, + label: "Sign in with Microsoft", + image: Image.asset( + "assets/images/microsoft_logo.png", + width: 40, + height: 30, ), ), + ), + const SizedBox(height: 5), + Align( + alignment: Alignment.center, + child: SmallClickableText( + "I already have an account", + onPressed: () { + context.pop(); + }, + ), ) - : Text( - 'Authenticated! Access token: ${client?.credentials.accessToken}'), - ), + ], + ), + ), + )), ); } } diff --git a/client_mobile/lib/main.dart b/client_mobile/lib/main.dart index 4488297..8f8a249 100644 --- a/client_mobile/lib/main.dart +++ b/client_mobile/lib/main.dart @@ -4,10 +4,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:go_router/go_router.dart'; +final GlobalKey navigatorKey = GlobalKey(); Future main() async { await dotenv.load(fileName: ".env"); final GoRouter router = GoRouter( + navigatorKey: navigatorKey, routes: [ GoRoute( path: '/', diff --git a/client_mobile/lib/services/microsoft/microsoft_auth_service.dart b/client_mobile/lib/services/microsoft/microsoft_auth_service.dart new file mode 100644 index 0000000..fc7eb3a --- /dev/null +++ b/client_mobile/lib/services/microsoft/microsoft_auth_service.dart @@ -0,0 +1,38 @@ +import 'package:aad_oauth/model/config.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:flutter/material.dart'; +import 'package:aad_oauth/aad_oauth.dart'; +import '../../main.dart'; + +class MicrosoftAuthService { + static final String clientId = dotenv.env["VITE_MICROSOFT_CLIENT_ID"] ?? ""; + static const String redirectUri = + "msauth://my.area.app/lvGC0B4SWYU8tNPHg%2FbdMjQinZQ%3D"; + static const String authority = "https://login.microsoftonline.com/common"; + static const FlutterSecureStorage secureStorage = FlutterSecureStorage(); + + static Future auth(BuildContext context) async { + final Config config = Config( + tenant: "common", + clientId: clientId, + scope: "https://graph.microsoft.com/.default", + navigatorKey: navigatorKey, + redirectUri: redirectUri); + config.webUseRedirect = false; + + final AadOAuth oauth = AadOAuth(config); + final result = await oauth.login(); + result.fold( + (l) => ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(l.message), + backgroundColor: Colors.red, + ), + ), + (r) async { + await secureStorage.write(key: 'microsoft_access_token', value: r.accessToken); + }, + ); + } +} diff --git a/client_mobile/lib/widgets/button.dart b/client_mobile/lib/widgets/button.dart index 1389341..3ca9261 100644 --- a/client_mobile/lib/widgets/button.dart +++ b/client_mobile/lib/widgets/button.dart @@ -34,8 +34,6 @@ class AreaButton extends StatelessWidget { fontSize: 24, color: Colors.white, )), - // const Spacer(), - // if (icon != null) FaIcon(size: 25, icon!), ), ); } diff --git a/client_mobile/lib/widgets/form_field.dart b/client_mobile/lib/widgets/form_field.dart index 116cdd3..cafcfb9 100644 --- a/client_mobile/lib/widgets/form_field.dart +++ b/client_mobile/lib/widgets/form_field.dart @@ -48,13 +48,12 @@ class AreaFormField extends StatelessWidget { color: Theme.of(context).colorScheme.onSurface, ), decoration: InputDecoration( - // fillColor: Theme.of(context).colorScheme., labelText: label, // Placeholder text border: const OutlineInputBorder(), enabledBorder: const OutlineInputBorder( borderSide: BorderSide( - color: Color.fromARGB(255, 221, 228, 222), // Couleur de la bordure lorsque le champ est actif - width: 2.0, // Largeur de la bordure + color: Color.fromARGB(255, 221, 228, 222), + width: 2.0, ), ), suffixIcon: suffixIcon, diff --git a/client_mobile/lib/widgets/sign_in_button.dart b/client_mobile/lib/widgets/sign_in_button.dart index ad982f1..827921c 100644 --- a/client_mobile/lib/widgets/sign_in_button.dart +++ b/client_mobile/lib/widgets/sign_in_button.dart @@ -1,12 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:font_awesome_flutter/font_awesome_flutter.dart'; class SignInButton extends StatelessWidget { const SignInButton( - {super.key, required this.label, this.icon, this.onPressed}); + {super.key, required this.label, this.image, this.onPressed}); final String label; - final FaIcon? icon; + final Image? image; final void Function()? onPressed; @override @@ -16,14 +15,14 @@ class SignInButton extends StatelessWidget { child: FilledButton( onPressed: onPressed ?? () {}, style: ButtonStyle( + padding: const WidgetStatePropertyAll(EdgeInsets.all(10)), backgroundColor: WidgetStateProperty.all(Colors.white), shape: WidgetStatePropertyAll( RoundedRectangleBorder( borderRadius: BorderRadius.circular(6.0), side: const BorderSide( - color: Color.fromARGB(255, 221, 228, - 222), // Couleur de la bordure lorsque le champ est actif - width: 2.0, // Largeur de la bordure + color: Color.fromARGB(255, 221, 228, 222), + width: 2.0, ), ), ), @@ -34,14 +33,15 @@ class SignInButton extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ - if (icon != null) icon!, - const SizedBox(width: 5), - Text(label, - style: const TextStyle( - fontFamily: "CoolveticaCondensed", - fontSize: 12, - color: Colors.black, - )), + if (image != null) image!, + Text( + label, + style: const TextStyle( + fontFamily: "CoolveticaCondensed", + fontSize: 12, + color: Colors.black, + ), + ), ], ), ), diff --git a/client_mobile/lib/widgets/simple_text.dart b/client_mobile/lib/widgets/simple_text.dart index 6f954ef..002461a 100644 --- a/client_mobile/lib/widgets/simple_text.dart +++ b/client_mobile/lib/widgets/simple_text.dart @@ -22,7 +22,6 @@ class SimpleText extends StatelessWidget { text, textAlign: textAlign, style: TextStyle( - // fontFamily: HodFonts.coolvetica, fontWeight: bold ? FontWeight.bold : null, fontSize: textSize, color: color, diff --git a/client_mobile/macos/Flutter/GeneratedPluginRegistrant.swift b/client_mobile/macos/Flutter/GeneratedPluginRegistrant.swift index 4f2a89c..0550540 100644 --- a/client_mobile/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/client_mobile/macos/Flutter/GeneratedPluginRegistrant.swift @@ -10,7 +10,9 @@ import flutter_secure_storage_macos import flutter_web_auth import flutter_web_auth_2 import path_provider_foundation +import shared_preferences_foundation import url_launcher_macos +import webview_flutter_wkwebview import window_to_front func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { @@ -19,6 +21,8 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FlutterWebAuthPlugin.register(with: registry.registrar(forPlugin: "FlutterWebAuthPlugin")) FlutterWebAuth2Plugin.register(with: registry.registrar(forPlugin: "FlutterWebAuth2Plugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) + FLTWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "FLTWebViewFlutterPlugin")) WindowToFrontPlugin.register(with: registry.registrar(forPlugin: "WindowToFrontPlugin")) } diff --git a/client_mobile/pubspec.lock b/client_mobile/pubspec.lock index cc5d156..467f5f1 100644 --- a/client_mobile/pubspec.lock +++ b/client_mobile/pubspec.lock @@ -1,6 +1,14 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + aad_oauth: + dependency: "direct main" + description: + name: aad_oauth + sha256: "7678046a7b4b5e967d324e7431626343084451e04ac847e382948c8e1286c30e" + url: "https://pub.dev" + source: hosted + version: "1.0.1" args: dependency: transitive description: @@ -65,6 +73,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.8" + dartz: + dependency: transitive + description: + name: dartz + sha256: e6acf34ad2e31b1eb00948692468c30ab48ac8250e0f0df661e29f12dd252168 + url: "https://pub.dev" + source: hosted + version: "0.10.1" dotenv: dependency: "direct main" description: @@ -73,6 +89,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.2.0" + equatable: + dependency: transitive + description: + name: equatable + sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7" + url: "https://pub.dev" + source: hosted + version: "2.0.7" fake_async: dependency: transitive description: @@ -89,6 +113,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.3" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" flutter: dependency: "direct main" description: flutter @@ -252,18 +284,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.4" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: @@ -300,18 +332,18 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.12.0" + version: "1.15.0" oauth2: dependency: "direct main" description: @@ -408,6 +440,62 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.1" + shared_preferences: + dependency: transitive + description: + name: shared_preferences + sha256: "95f9997ca1fb9799d494d0cb2a780fd7be075818d59f00c43832ed112b158a82" + url: "https://pub.dev" + source: hosted + version: "2.3.3" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "7f172d1b06de5da47b6264c2692ee2ead20bbbc246690427cdb4fc301cd0c549" + url: "https://pub.dev" + source: hosted + version: "2.3.4" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "07e050c7cd39bad516f8d64c455f04508d09df104be326d8c02551590a0d513d" + url: "https://pub.dev" + source: hosted + version: "2.5.3" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e + url: "https://pub.dev" + source: hosted + version: "2.4.2" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" sky_engine: dependency: transitive description: flutter @@ -457,10 +545,10 @@ packages: dependency: transitive description: name: test_api - sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.7.0" + version: "0.7.2" typed_data: dependency: transitive description: @@ -545,10 +633,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "14.2.1" + version: "14.2.5" web: dependency: transitive description: @@ -557,6 +645,38 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + webview_flutter: + dependency: transitive + description: + name: webview_flutter + sha256: "889a0a678e7c793c308c68739996227c9661590605e70b1f6cf6b9a6634f7aec" + url: "https://pub.dev" + source: hosted + version: "4.10.0" + webview_flutter_android: + dependency: transitive + description: + name: webview_flutter_android + sha256: "285cedfd9441267f6cca8843458620b5fda1af75b04f5818d0441acda5d7df19" + url: "https://pub.dev" + source: hosted + version: "4.1.0" + webview_flutter_platform_interface: + dependency: transitive + description: + name: webview_flutter_platform_interface + sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d + url: "https://pub.dev" + source: hosted + version: "2.10.0" + webview_flutter_wkwebview: + dependency: transitive + description: + name: webview_flutter_wkwebview + sha256: b7e92f129482460951d96ef9a46b49db34bd2e1621685de26e9eaafd9674e7eb + url: "https://pub.dev" + source: hosted + version: "3.16.3" win32: dependency: transitive description: @@ -582,5 +702,5 @@ packages: source: hosted version: "1.1.0" sdks: - dart: ">=3.4.1 <4.0.0" - flutter: ">=3.22.0" + dart: ">=3.5.0 <4.0.0" + flutter: ">=3.24.0" diff --git a/client_mobile/pubspec.yaml b/client_mobile/pubspec.yaml index 664d0f6..a5640fa 100644 --- a/client_mobile/pubspec.yaml +++ b/client_mobile/pubspec.yaml @@ -43,6 +43,7 @@ dependencies: flutter_dotenv: ^5.2.1 font_awesome_flutter: ^10.8.0 go_router: ^14.6.1 + aad_oauth: ^1.0.1 dev_dependencies: flutter_test: @@ -69,6 +70,7 @@ flutter: # To add assets to your application, add an assets section, like this: assets: - .env.mobile + - assets/images/microsoft_logo.png # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg