feat: implement social login functionality with Google, Facebook, and Twitter, including API integration and platform-specific configurations.
This commit is contained in:
@@ -37,6 +37,27 @@
|
|||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.google.firebase.messaging.default_notification_channel_id"
|
android:name="com.google.firebase.messaging.default_notification_channel_id"
|
||||||
android:value="high_importance_channel" />
|
android:value="high_importance_channel" />
|
||||||
|
<!-- Facebook Login -->
|
||||||
|
<meta-data
|
||||||
|
android:name="com.facebook.sdk.ApplicationId"
|
||||||
|
android:value="@string/facebook_app_id" />
|
||||||
|
<meta-data
|
||||||
|
android:name="com.facebook.sdk.ClientToken"
|
||||||
|
android:value="@string/facebook_client_token" />
|
||||||
|
<activity
|
||||||
|
android:name="com.facebook.FacebookActivity"
|
||||||
|
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
|
||||||
|
android:label="@string/app_name" />
|
||||||
|
<activity
|
||||||
|
android:name="com.facebook.CustomTabActivity"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:scheme="@string/fb_login_protocol_scheme" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
<!-- Required to query activities that can process text, see:
|
<!-- Required to query activities that can process text, see:
|
||||||
https://developer.android.com/training/package-visibility and
|
https://developer.android.com/training/package-visibility and
|
||||||
|
|||||||
6
android/app/src/main/res/values/strings.xml
Normal file
6
android/app/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="facebook_app_id">2124098594797306</string>
|
||||||
|
<string name="facebook_client_token">c7ed8c0d68a517cca1cd0e6668282410</string>
|
||||||
|
<string name="fb_login_protocol_scheme">fb2124098594797306</string>
|
||||||
|
</resources>
|
||||||
@@ -1,6 +1,24 @@
|
|||||||
PODS:
|
PODS:
|
||||||
|
- AppAuth (1.7.6):
|
||||||
|
- AppAuth/Core (= 1.7.6)
|
||||||
|
- AppAuth/ExternalUserAgent (= 1.7.6)
|
||||||
|
- AppAuth/Core (1.7.6)
|
||||||
|
- AppAuth/ExternalUserAgent (1.7.6):
|
||||||
|
- AppAuth/Core
|
||||||
|
- AppCheckCore (11.2.0):
|
||||||
|
- GoogleUtilities/Environment (~> 8.0)
|
||||||
|
- GoogleUtilities/UserDefaults (~> 8.0)
|
||||||
|
- PromisesObjC (~> 2.4)
|
||||||
- emoji_picker_flutter (0.0.1):
|
- emoji_picker_flutter (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- FBAEMKit (18.0.2):
|
||||||
|
- FBSDKCoreKit_Basics (= 18.0.2)
|
||||||
|
- FBSDKCoreKit (18.0.2):
|
||||||
|
- FBAEMKit (= 18.0.2)
|
||||||
|
- FBSDKCoreKit_Basics (= 18.0.2)
|
||||||
|
- FBSDKCoreKit_Basics (18.0.2)
|
||||||
|
- FBSDKLoginKit (18.0.2):
|
||||||
|
- FBSDKCoreKit (= 18.0.2)
|
||||||
- Firebase/CoreOnly (11.15.0):
|
- Firebase/CoreOnly (11.15.0):
|
||||||
- FirebaseCore (~> 11.15.0)
|
- FirebaseCore (~> 11.15.0)
|
||||||
- Firebase/Messaging (11.15.0):
|
- Firebase/Messaging (11.15.0):
|
||||||
@@ -34,13 +52,27 @@ PODS:
|
|||||||
- GoogleUtilities/UserDefaults (~> 8.1)
|
- GoogleUtilities/UserDefaults (~> 8.1)
|
||||||
- nanopb (~> 3.30910.0)
|
- nanopb (~> 3.30910.0)
|
||||||
- Flutter (1.0.0)
|
- Flutter (1.0.0)
|
||||||
|
- flutter_facebook_auth (7.1.5):
|
||||||
|
- FBSDKLoginKit (= 18.0.2)
|
||||||
|
- Flutter
|
||||||
- flutter_local_notifications (0.0.1):
|
- flutter_local_notifications (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- flutter_secure_storage (6.0.0):
|
- flutter_secure_storage (6.0.0):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- google_sign_in_ios (0.0.1):
|
||||||
|
- AppAuth (>= 1.7.4)
|
||||||
|
- Flutter
|
||||||
|
- FlutterMacOS
|
||||||
|
- GoogleSignIn (~> 8.0)
|
||||||
|
- GTMSessionFetcher (>= 3.4.0)
|
||||||
- GoogleDataTransport (10.1.0):
|
- GoogleDataTransport (10.1.0):
|
||||||
- nanopb (~> 3.30910.0)
|
- nanopb (~> 3.30910.0)
|
||||||
- PromisesObjC (~> 2.4)
|
- PromisesObjC (~> 2.4)
|
||||||
|
- GoogleSignIn (8.0.0):
|
||||||
|
- AppAuth (< 2.0, >= 1.7.3)
|
||||||
|
- AppCheckCore (~> 11.0)
|
||||||
|
- GTMAppAuth (< 5.0, >= 4.1.1)
|
||||||
|
- GTMSessionFetcher/Core (~> 3.3)
|
||||||
- GoogleUtilities/AppDelegateSwizzler (8.1.0):
|
- GoogleUtilities/AppDelegateSwizzler (8.1.0):
|
||||||
- GoogleUtilities/Environment
|
- GoogleUtilities/Environment
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
@@ -65,6 +97,14 @@ PODS:
|
|||||||
- GoogleUtilities/UserDefaults (8.1.0):
|
- GoogleUtilities/UserDefaults (8.1.0):
|
||||||
- GoogleUtilities/Logger
|
- GoogleUtilities/Logger
|
||||||
- GoogleUtilities/Privacy
|
- GoogleUtilities/Privacy
|
||||||
|
- GTMAppAuth (4.1.1):
|
||||||
|
- AppAuth/Core (~> 1.7)
|
||||||
|
- GTMSessionFetcher/Core (< 4.0, >= 3.3)
|
||||||
|
- GTMSessionFetcher (3.5.0):
|
||||||
|
- GTMSessionFetcher/Full (= 3.5.0)
|
||||||
|
- GTMSessionFetcher/Core (3.5.0)
|
||||||
|
- GTMSessionFetcher/Full (3.5.0):
|
||||||
|
- GTMSessionFetcher/Core
|
||||||
- image_picker_ios (0.0.1):
|
- image_picker_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- nanopb (3.30910.0):
|
- nanopb (3.30910.0):
|
||||||
@@ -84,6 +124,8 @@ PODS:
|
|||||||
- sqflite_darwin (0.0.4):
|
- sqflite_darwin (0.0.4):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
|
- twitter_login (0.0.1):
|
||||||
|
- Flutter
|
||||||
- url_launcher_ios (0.0.1):
|
- url_launcher_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- webview_flutter_wkwebview (0.0.1):
|
- webview_flutter_wkwebview (0.0.1):
|
||||||
@@ -95,25 +137,37 @@ DEPENDENCIES:
|
|||||||
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
|
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
|
||||||
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
|
||||||
- Flutter (from `Flutter`)
|
- Flutter (from `Flutter`)
|
||||||
|
- flutter_facebook_auth (from `.symlinks/plugins/flutter_facebook_auth/ios`)
|
||||||
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
|
||||||
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
|
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
|
||||||
|
- google_sign_in_ios (from `.symlinks/plugins/google_sign_in_ios/darwin`)
|
||||||
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
||||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||||
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
|
||||||
|
- twitter_login (from `.symlinks/plugins/twitter_login/ios`)
|
||||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||||
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`)
|
- webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`)
|
||||||
|
|
||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
trunk:
|
trunk:
|
||||||
|
- AppAuth
|
||||||
|
- AppCheckCore
|
||||||
|
- FBAEMKit
|
||||||
|
- FBSDKCoreKit
|
||||||
|
- FBSDKCoreKit_Basics
|
||||||
|
- FBSDKLoginKit
|
||||||
- Firebase
|
- Firebase
|
||||||
- FirebaseCore
|
- FirebaseCore
|
||||||
- FirebaseCoreInternal
|
- FirebaseCoreInternal
|
||||||
- FirebaseInstallations
|
- FirebaseInstallations
|
||||||
- FirebaseMessaging
|
- FirebaseMessaging
|
||||||
- GoogleDataTransport
|
- GoogleDataTransport
|
||||||
|
- GoogleSignIn
|
||||||
- GoogleUtilities
|
- GoogleUtilities
|
||||||
|
- GTMAppAuth
|
||||||
|
- GTMSessionFetcher
|
||||||
- nanopb
|
- nanopb
|
||||||
- PromisesObjC
|
- PromisesObjC
|
||||||
|
|
||||||
@@ -126,10 +180,14 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/firebase_messaging/ios"
|
:path: ".symlinks/plugins/firebase_messaging/ios"
|
||||||
Flutter:
|
Flutter:
|
||||||
:path: Flutter
|
:path: Flutter
|
||||||
|
flutter_facebook_auth:
|
||||||
|
:path: ".symlinks/plugins/flutter_facebook_auth/ios"
|
||||||
flutter_local_notifications:
|
flutter_local_notifications:
|
||||||
:path: ".symlinks/plugins/flutter_local_notifications/ios"
|
:path: ".symlinks/plugins/flutter_local_notifications/ios"
|
||||||
flutter_secure_storage:
|
flutter_secure_storage:
|
||||||
:path: ".symlinks/plugins/flutter_secure_storage/ios"
|
:path: ".symlinks/plugins/flutter_secure_storage/ios"
|
||||||
|
google_sign_in_ios:
|
||||||
|
:path: ".symlinks/plugins/google_sign_in_ios/darwin"
|
||||||
image_picker_ios:
|
image_picker_ios:
|
||||||
:path: ".symlinks/plugins/image_picker_ios/ios"
|
:path: ".symlinks/plugins/image_picker_ios/ios"
|
||||||
package_info_plus:
|
package_info_plus:
|
||||||
@@ -140,13 +198,21 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
||||||
sqflite_darwin:
|
sqflite_darwin:
|
||||||
:path: ".symlinks/plugins/sqflite_darwin/darwin"
|
:path: ".symlinks/plugins/sqflite_darwin/darwin"
|
||||||
|
twitter_login:
|
||||||
|
:path: ".symlinks/plugins/twitter_login/ios"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||||
webview_flutter_wkwebview:
|
webview_flutter_wkwebview:
|
||||||
:path: ".symlinks/plugins/webview_flutter_wkwebview/darwin"
|
:path: ".symlinks/plugins/webview_flutter_wkwebview/darwin"
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
|
AppAuth: d4f13a8fe0baf391b2108511793e4b479691fb73
|
||||||
|
AppCheckCore: cc8fd0a3a230ddd401f326489c99990b013f0c4f
|
||||||
emoji_picker_flutter: 8e50ec5caac456a23a78637e02c6293ea0ac8771
|
emoji_picker_flutter: 8e50ec5caac456a23a78637e02c6293ea0ac8771
|
||||||
|
FBAEMKit: 56a4f5a9607957b547b6458b17a98c5bb2736367
|
||||||
|
FBSDKCoreKit: 54f1240567e16862ab71c53c33dc347db5c524c5
|
||||||
|
FBSDKCoreKit_Basics: eb530cd6a79030dbb11df460aafb2767bcad9028
|
||||||
|
FBSDKLoginKit: 6a70798793e499335a98fab1a758d7da34af196e
|
||||||
Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e
|
Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e
|
||||||
firebase_core: 99a37263b3c27536063a7b601d9e2a49400a433c
|
firebase_core: 99a37263b3c27536063a7b601d9e2a49400a433c
|
||||||
firebase_messaging: bf6697c61f31c7cc0f654131212ff04c0115c2c7
|
firebase_messaging: bf6697c61f31c7cc0f654131212ff04c0115c2c7
|
||||||
@@ -155,10 +221,15 @@ SPEC CHECKSUMS:
|
|||||||
FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843
|
FirebaseInstallations: 317270fec08a5d418fdbc8429282238cab3ac843
|
||||||
FirebaseMessaging: 3b26e2cee503815e01c3701236b020aa9b576f09
|
FirebaseMessaging: 3b26e2cee503815e01c3701236b020aa9b576f09
|
||||||
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
|
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
|
||||||
|
flutter_facebook_auth: 08ab1a6be157d7fce8348b881787e7608f763267
|
||||||
flutter_local_notifications: df98d66e515e1ca797af436137b4459b160ad8c9
|
flutter_local_notifications: df98d66e515e1ca797af436137b4459b160ad8c9
|
||||||
flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
|
flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
|
||||||
|
google_sign_in_ios: 7411fab6948df90490dc4620ecbcabdc3ca04017
|
||||||
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
||||||
|
GoogleSignIn: ce8c89bb9b37fb624b92e7514cc67335d1e277e4
|
||||||
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
||||||
|
GTMAppAuth: f69bd07d68cd3b766125f7e072c45d7340dea0de
|
||||||
|
GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6
|
||||||
image_picker_ios: 4f2f91b01abdb52842a8e277617df877e40f905b
|
image_picker_ios: 4f2f91b01abdb52842a8e277617df877e40f905b
|
||||||
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
|
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
|
||||||
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
|
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
|
||||||
@@ -166,6 +237,7 @@ SPEC CHECKSUMS:
|
|||||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||||
shared_preferences_foundation: 5086985c1d43c5ba4d5e69a4e8083a389e2909e6
|
shared_preferences_foundation: 5086985c1d43c5ba4d5e69a4e8083a389e2909e6
|
||||||
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
|
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
|
||||||
|
twitter_login: 2794db69b7640681171b17b3c2c84ad9dfb4a57f
|
||||||
url_launcher_ios: bb13df5870e8c4234ca12609d04010a21be43dfa
|
url_launcher_ios: bb13df5870e8c4234ca12609d04010a21be43dfa
|
||||||
webview_flutter_wkwebview: 29eb20d43355b48fe7d07113835b9128f84e3af4
|
webview_flutter_wkwebview: 29eb20d43355b48fe7d07113835b9128f84e3af4
|
||||||
|
|
||||||
|
|||||||
@@ -47,9 +47,26 @@
|
|||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
|
<key>CFBundleURLTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>fb2124098594797306</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>FacebookAppID</key>
|
||||||
|
<string>2124098594797306</string>
|
||||||
|
<key>FacebookClientToken</key>
|
||||||
|
<string>c7ed8c0d68a517cca1cd0e6668282410</string>
|
||||||
|
<key>FacebookDisplayName</key>
|
||||||
|
<string>RE-Quest</string>
|
||||||
<key>LSApplicationQueriesSchemes</key>
|
<key>LSApplicationQueriesSchemes</key>
|
||||||
<array>
|
<array>
|
||||||
<string>mailto</string>
|
<string>mailto</string>
|
||||||
|
<string>fbapi</string>
|
||||||
|
<string>fb-messenger-share-api</string>
|
||||||
</array>
|
</array>
|
||||||
<key>NSPhotoLibraryUsageDescription</key>
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
<string>We need access to your photo library to set your profile photo.</string>
|
<string>We need access to your photo library to set your profile photo.</string>
|
||||||
|
|||||||
@@ -39,4 +39,7 @@ class ApiConstants {
|
|||||||
// 2FA
|
// 2FA
|
||||||
static const String twoFactorVerify = '/auth/2fa/verify';
|
static const String twoFactorVerify = '/auth/2fa/verify';
|
||||||
static const String twoFactorVerifyBackup = '/auth/2fa/verify-backup';
|
static const String twoFactorVerifyBackup = '/auth/2fa/verify-backup';
|
||||||
|
|
||||||
|
// Social Auth
|
||||||
|
static const String authSocial = '/auth/social';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -308,6 +308,13 @@ class _AgentDetailScreenState extends ConsumerState<AgentDetailScreen> {
|
|||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
if (conversationId != null) {
|
if (conversationId != null) {
|
||||||
context.push('/messages/chat/$conversationId');
|
context.push('/messages/chat/$conversationId');
|
||||||
|
} else {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Text('You need to be connected to send messages.'),
|
||||||
|
behavior: SnackBarBehavior.floating,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (mounted) setState(() => _isStartingConversation = false);
|
if (mounted) setState(() => _isStartingConversation = false);
|
||||||
|
|||||||
@@ -130,6 +130,44 @@ class AuthRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Social auth (Google, Facebook, etc.) — calls POST /auth/social
|
||||||
|
Future<UserModel> socialAuth({
|
||||||
|
required String provider,
|
||||||
|
required String providerId,
|
||||||
|
required String email,
|
||||||
|
String? name,
|
||||||
|
String? avatar,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
final response = await _dio.post(
|
||||||
|
ApiConstants.authSocial,
|
||||||
|
data: {
|
||||||
|
'provider': provider,
|
||||||
|
'providerId': providerId,
|
||||||
|
'email': email,
|
||||||
|
if (name != null) 'name': name,
|
||||||
|
if (avatar != null) 'avatar': avatar,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
final data = response.data['data'] as Map<String, dynamic>;
|
||||||
|
final authResponse = AuthResponse.fromJson(data);
|
||||||
|
|
||||||
|
await SecureStorage.saveTokens(
|
||||||
|
accessToken: authResponse.accessToken,
|
||||||
|
refreshToken: authResponse.refreshToken,
|
||||||
|
);
|
||||||
|
|
||||||
|
return authResponse.user;
|
||||||
|
} on DioException catch (e) {
|
||||||
|
if (e.error is ApiException) throw e.error as ApiException;
|
||||||
|
throw ApiException(
|
||||||
|
message: e.message ?? 'Social login failed',
|
||||||
|
statusCode: e.response?.statusCode,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Register returns { message, user } — no tokens.
|
/// Register returns { message, user } — no tokens.
|
||||||
/// The user must verify their email before logging in.
|
/// The user must verify their email before logging in.
|
||||||
Future<Map<String, dynamic>> register(RegisterRequest request) async {
|
Future<Map<String, dynamic>> register(RegisterRequest request) async {
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter_facebook_auth/flutter_facebook_auth.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:google_sign_in/google_sign_in.dart';
|
||||||
import 'package:real_estate_mobile/core/network/api_client.dart';
|
import 'package:real_estate_mobile/core/network/api_client.dart';
|
||||||
import 'package:real_estate_mobile/core/network/api_exceptions.dart';
|
import 'package:real_estate_mobile/core/network/api_exceptions.dart';
|
||||||
import 'package:real_estate_mobile/core/services/push_notification_service.dart';
|
import 'package:real_estate_mobile/core/services/push_notification_service.dart';
|
||||||
@@ -7,6 +10,7 @@ import 'package:real_estate_mobile/features/auth/data/auth_repository.dart';
|
|||||||
import 'package:real_estate_mobile/features/auth/data/models/register_request.dart';
|
import 'package:real_estate_mobile/features/auth/data/models/register_request.dart';
|
||||||
import 'package:real_estate_mobile/features/auth/data/models/user_model.dart';
|
import 'package:real_estate_mobile/features/auth/data/models/user_model.dart';
|
||||||
import 'package:real_estate_mobile/features/messaging/data/socket_service.dart';
|
import 'package:real_estate_mobile/features/messaging/data/socket_service.dart';
|
||||||
|
import 'package:twitter_login/twitter_login.dart';
|
||||||
|
|
||||||
// Auth state
|
// Auth state
|
||||||
enum AuthStatus { initial, loading, authenticated, error }
|
enum AuthStatus { initial, loading, authenticated, error }
|
||||||
@@ -170,6 +174,182 @@ class AuthNotifier extends StateNotifier<AuthState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> signInWithGoogle() async {
|
||||||
|
state = state.copyWith(
|
||||||
|
status: AuthStatus.loading,
|
||||||
|
errorMessage: null,
|
||||||
|
fieldErrors: [],
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final googleSignIn = GoogleSignIn(
|
||||||
|
scopes: ['email', 'profile'],
|
||||||
|
serverClientId: '721413957511-goij5fnpal64o86vcppmkh743jhiv4nj.apps.googleusercontent.com',
|
||||||
|
);
|
||||||
|
final account = await googleSignIn.signIn();
|
||||||
|
|
||||||
|
if (account == null) {
|
||||||
|
// User cancelled
|
||||||
|
state = state.copyWith(status: AuthStatus.initial);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final user = await _repository.socialAuth(
|
||||||
|
provider: 'google',
|
||||||
|
providerId: account.id,
|
||||||
|
email: account.email,
|
||||||
|
name: account.displayName,
|
||||||
|
avatar: account.photoUrl,
|
||||||
|
);
|
||||||
|
|
||||||
|
state = state.copyWith(
|
||||||
|
status: AuthStatus.authenticated,
|
||||||
|
user: user,
|
||||||
|
);
|
||||||
|
_connectSocket();
|
||||||
|
_initPushNotifications();
|
||||||
|
} on ApiException catch (e) {
|
||||||
|
state = state.copyWith(
|
||||||
|
status: AuthStatus.error,
|
||||||
|
errorMessage: e.message,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('Google sign-in error: $e');
|
||||||
|
state = state.copyWith(
|
||||||
|
status: AuthStatus.error,
|
||||||
|
errorMessage: 'Google sign-in failed. Please try again.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> signInWithFacebook() async {
|
||||||
|
state = state.copyWith(
|
||||||
|
status: AuthStatus.loading,
|
||||||
|
errorMessage: null,
|
||||||
|
fieldErrors: [],
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final result = await FacebookAuth.instance.login(
|
||||||
|
permissions: ['email', 'public_profile'],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.status == LoginStatus.cancelled) {
|
||||||
|
state = state.copyWith(status: AuthStatus.initial);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.status != LoginStatus.success) {
|
||||||
|
state = state.copyWith(
|
||||||
|
status: AuthStatus.error,
|
||||||
|
errorMessage: result.message ?? 'Facebook login failed',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final userData = await FacebookAuth.instance.getUserData(
|
||||||
|
fields: 'id,name,email,picture.width(200)',
|
||||||
|
);
|
||||||
|
|
||||||
|
final email = userData['email'] as String?;
|
||||||
|
if (email == null || email.isEmpty) {
|
||||||
|
state = state.copyWith(
|
||||||
|
status: AuthStatus.error,
|
||||||
|
errorMessage: 'Email not available from Facebook. Please use email login.',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final pictureData = userData['picture']?['data'];
|
||||||
|
final avatarUrl = pictureData?['url'] as String?;
|
||||||
|
|
||||||
|
final user = await _repository.socialAuth(
|
||||||
|
provider: 'facebook',
|
||||||
|
providerId: userData['id'] as String,
|
||||||
|
email: email,
|
||||||
|
name: userData['name'] as String?,
|
||||||
|
avatar: avatarUrl,
|
||||||
|
);
|
||||||
|
|
||||||
|
state = state.copyWith(
|
||||||
|
status: AuthStatus.authenticated,
|
||||||
|
user: user,
|
||||||
|
);
|
||||||
|
_connectSocket();
|
||||||
|
_initPushNotifications();
|
||||||
|
} on ApiException catch (e) {
|
||||||
|
state = state.copyWith(
|
||||||
|
status: AuthStatus.error,
|
||||||
|
errorMessage: e.message,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('Facebook sign-in error: $e');
|
||||||
|
state = state.copyWith(
|
||||||
|
status: AuthStatus.error,
|
||||||
|
errorMessage: 'Facebook sign-in failed. Please try again.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> signInWithTwitter() async {
|
||||||
|
state = state.copyWith(
|
||||||
|
status: AuthStatus.loading,
|
||||||
|
errorMessage: null,
|
||||||
|
fieldErrors: [],
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final twitterLogin = TwitterLogin(
|
||||||
|
apiKey: 'eWEzaDJ0al9lX1diOGY0ejRYeXM6MTpjaQ',
|
||||||
|
apiSecretKey: 'HadGMSRKKswfXOajbmggrnmLAn9cxJsl8GtFxGHqjX-CJ0A2Tu',
|
||||||
|
redirectURI: 'request://',
|
||||||
|
);
|
||||||
|
|
||||||
|
final authResult = await twitterLogin.login();
|
||||||
|
|
||||||
|
if (authResult.status == TwitterLoginStatus.cancelledByUser) {
|
||||||
|
state = state.copyWith(status: AuthStatus.initial);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authResult.status != TwitterLoginStatus.loggedIn) {
|
||||||
|
state = state.copyWith(
|
||||||
|
status: AuthStatus.error,
|
||||||
|
errorMessage: authResult.errorMessage ?? 'Twitter login failed',
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final twitterUser = authResult.user!;
|
||||||
|
|
||||||
|
final user = await _repository.socialAuth(
|
||||||
|
provider: 'twitter',
|
||||||
|
providerId: twitterUser.id.toString(),
|
||||||
|
email: '${twitterUser.screenName}@twitter.placeholder',
|
||||||
|
name: twitterUser.name,
|
||||||
|
avatar: twitterUser.thumbnailImage,
|
||||||
|
);
|
||||||
|
|
||||||
|
state = state.copyWith(
|
||||||
|
status: AuthStatus.authenticated,
|
||||||
|
user: user,
|
||||||
|
);
|
||||||
|
_connectSocket();
|
||||||
|
_initPushNotifications();
|
||||||
|
} on ApiException catch (e) {
|
||||||
|
state = state.copyWith(
|
||||||
|
status: AuthStatus.error,
|
||||||
|
errorMessage: e.message,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('Twitter sign-in error: $e');
|
||||||
|
state = state.copyWith(
|
||||||
|
status: AuthStatus.error,
|
||||||
|
errorMessage: 'Twitter sign-in failed. Please try again.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> register({
|
Future<void> register({
|
||||||
required String name,
|
required String name,
|
||||||
required String email,
|
required String email,
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
import 'package:real_estate_mobile/core/constants/app_colors.dart';
|
||||||
|
import 'package:real_estate_mobile/features/auth/presentation/providers/auth_provider.dart';
|
||||||
|
|
||||||
class SocialLoginButtons extends StatelessWidget {
|
class SocialLoginButtons extends ConsumerWidget {
|
||||||
const SocialLoginButtons({super.key});
|
const SocialLoginButtons({super.key});
|
||||||
|
|
||||||
void _showComingSoon(BuildContext context) {
|
void _showComingSoon(BuildContext context) {
|
||||||
@@ -16,13 +18,16 @@ class SocialLoginButtons extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final authState = ref.watch(authProvider);
|
||||||
|
final isLoading = authState.status == AuthStatus.loading;
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
// Apple
|
// Apple
|
||||||
_SocialButton(
|
_SocialButton(
|
||||||
onTap: () => _showComingSoon(context),
|
onTap: isLoading ? null : () => _showComingSoon(context),
|
||||||
child: const Icon(
|
child: const Icon(
|
||||||
Icons.apple,
|
Icons.apple,
|
||||||
size: 28,
|
size: 28,
|
||||||
@@ -32,7 +37,9 @@ class SocialLoginButtons extends StatelessWidget {
|
|||||||
const SizedBox(width: 32),
|
const SizedBox(width: 32),
|
||||||
// Google
|
// Google
|
||||||
_SocialButton(
|
_SocialButton(
|
||||||
onTap: () => _showComingSoon(context),
|
onTap: isLoading
|
||||||
|
? null
|
||||||
|
: () => ref.read(authProvider.notifier).signInWithGoogle(),
|
||||||
child: SvgPicture.asset(
|
child: SvgPicture.asset(
|
||||||
'assets/icons/google.svg',
|
'assets/icons/google.svg',
|
||||||
width: 24,
|
width: 24,
|
||||||
@@ -42,7 +49,9 @@ class SocialLoginButtons extends StatelessWidget {
|
|||||||
const SizedBox(width: 32),
|
const SizedBox(width: 32),
|
||||||
// X (Twitter)
|
// X (Twitter)
|
||||||
_SocialButton(
|
_SocialButton(
|
||||||
onTap: () => _showComingSoon(context),
|
onTap: isLoading
|
||||||
|
? null
|
||||||
|
: () => ref.read(authProvider.notifier).signInWithTwitter(),
|
||||||
child: SvgPicture.asset(
|
child: SvgPicture.asset(
|
||||||
'assets/icons/x.svg',
|
'assets/icons/x.svg',
|
||||||
width: 24,
|
width: 24,
|
||||||
@@ -52,7 +61,9 @@ class SocialLoginButtons extends StatelessWidget {
|
|||||||
const SizedBox(width: 32),
|
const SizedBox(width: 32),
|
||||||
// Facebook
|
// Facebook
|
||||||
_SocialButton(
|
_SocialButton(
|
||||||
onTap: () => _showComingSoon(context),
|
onTap: isLoading
|
||||||
|
? null
|
||||||
|
: () => ref.read(authProvider.notifier).signInWithFacebook(),
|
||||||
child: SvgPicture.asset(
|
child: SvgPicture.asset(
|
||||||
'assets/icons/facebook.svg',
|
'assets/icons/facebook.svg',
|
||||||
width: 24,
|
width: 24,
|
||||||
@@ -65,7 +76,7 @@ class SocialLoginButtons extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _SocialButton extends StatelessWidget {
|
class _SocialButton extends StatelessWidget {
|
||||||
final VoidCallback onTap;
|
final VoidCallback? onTap;
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|
||||||
const _SocialButton({
|
const _SocialButton({
|
||||||
@@ -77,11 +88,14 @@ class _SocialButton extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
|
child: Opacity(
|
||||||
|
opacity: onTap != null ? 1.0 : 0.5,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 40,
|
width: 40,
|
||||||
height: 40,
|
height: 40,
|
||||||
child: Center(child: child),
|
child: Center(child: child),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -327,6 +327,8 @@ class _TopProfessionalsSectionState
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(16, 12, 16, 12),
|
padding: const EdgeInsets.fromLTRB(16, 12, 16, 12),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@@ -517,6 +519,7 @@ class _TopProfessionalsSectionState
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -423,7 +423,7 @@ class MessagingNotifier extends StateNotifier<MessagingState> {
|
|||||||
conversations: updatedConversations,
|
conversations: updatedConversations,
|
||||||
isSending: false,
|
isSending: false,
|
||||||
);
|
);
|
||||||
} catch (_) {
|
} catch (e) {
|
||||||
final messagesAfterError =
|
final messagesAfterError =
|
||||||
List<ChatMessage>.from(state.messages[conversationId] ?? []);
|
List<ChatMessage>.from(state.messages[conversationId] ?? []);
|
||||||
messagesAfterError.removeWhere((m) => m.id == tempId);
|
messagesAfterError.removeWhere((m) => m.id == tempId);
|
||||||
@@ -432,10 +432,15 @@ class MessagingNotifier extends StateNotifier<MessagingState> {
|
|||||||
Map<String, List<ChatMessage>>.from(state.messages)
|
Map<String, List<ChatMessage>>.from(state.messages)
|
||||||
..[conversationId] = messagesAfterError;
|
..[conversationId] = messagesAfterError;
|
||||||
|
|
||||||
|
// Show specific error for connection-required failures
|
||||||
|
final errorMsg = e.toString().contains('connection')
|
||||||
|
? 'You must be connected to send messages'
|
||||||
|
: 'Failed to send message';
|
||||||
|
|
||||||
state = state.copyWith(
|
state = state.copyWith(
|
||||||
messages: errorMessages,
|
messages: errorMessages,
|
||||||
isSending: false,
|
isSending: false,
|
||||||
error: 'Failed to send message',
|
error: errorMsg,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,29 +6,35 @@ import FlutterMacOS
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
import emoji_picker_flutter
|
import emoji_picker_flutter
|
||||||
|
import facebook_auth_desktop
|
||||||
import file_selector_macos
|
import file_selector_macos
|
||||||
import firebase_core
|
import firebase_core
|
||||||
import firebase_messaging
|
import firebase_messaging
|
||||||
import flutter_local_notifications
|
import flutter_local_notifications
|
||||||
import flutter_secure_storage_macos
|
import flutter_secure_storage_macos
|
||||||
|
import google_sign_in_ios
|
||||||
import package_info_plus
|
import package_info_plus
|
||||||
import path_provider_foundation
|
import path_provider_foundation
|
||||||
import shared_preferences_foundation
|
import shared_preferences_foundation
|
||||||
import sqflite_darwin
|
import sqflite_darwin
|
||||||
|
import twitter_login
|
||||||
import url_launcher_macos
|
import url_launcher_macos
|
||||||
import webview_flutter_wkwebview
|
import webview_flutter_wkwebview
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
EmojiPickerFlutterPlugin.register(with: registry.registrar(forPlugin: "EmojiPickerFlutterPlugin"))
|
EmojiPickerFlutterPlugin.register(with: registry.registrar(forPlugin: "EmojiPickerFlutterPlugin"))
|
||||||
|
FacebookAuthDesktopPlugin.register(with: registry.registrar(forPlugin: "FacebookAuthDesktopPlugin"))
|
||||||
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
|
||||||
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
|
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
|
||||||
FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin"))
|
FLTFirebaseMessagingPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseMessagingPlugin"))
|
||||||
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
|
||||||
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
||||||
|
FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin"))
|
||||||
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
|
||||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
|
||||||
|
TwitterLoginPlugin.register(with: registry.registrar(forPlugin: "TwitterLoginPlugin"))
|
||||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||||
WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin"))
|
WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin"))
|
||||||
}
|
}
|
||||||
|
|||||||
88
pubspec.lock
88
pubspec.lock
@@ -289,6 +289,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.4.0"
|
version: "4.4.0"
|
||||||
|
facebook_auth_desktop:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: facebook_auth_desktop
|
||||||
|
sha256: "219d559a33891e937c1913430505eae01fb946cb35729167bbdc747e3ebbd9ff"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -422,6 +430,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.2.1"
|
version: "5.2.1"
|
||||||
|
flutter_facebook_auth:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_facebook_auth
|
||||||
|
sha256: f4652480123fa22d02c8fd3cb890246bf3358d1e9928fc5f576c3d1b0faf2acc
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.1.5"
|
||||||
|
flutter_facebook_auth_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_facebook_auth_platform_interface
|
||||||
|
sha256: e04b8dbfa77702bea45a79993163ad5d20b2c0084109bec591fdc2b9ee505779
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.1.2"
|
||||||
|
flutter_facebook_auth_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_facebook_auth_web
|
||||||
|
sha256: f682400d61cf8d52dd8b6458b5ee106ed57e95309a117dc32875d3da129ce47c
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.1.2"
|
||||||
flutter_flavorizr:
|
flutter_flavorizr:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@@ -592,6 +624,54 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "14.8.1"
|
version: "14.8.1"
|
||||||
|
google_identity_services_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: google_identity_services_web
|
||||||
|
sha256: "5d187c46dc59e02646e10fe82665fc3884a9b71bc1c90c2b8b749316d33ee454"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.3+1"
|
||||||
|
google_sign_in:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: google_sign_in
|
||||||
|
sha256: d0a2c3bcb06e607bb11e4daca48bd4b6120f0bbc4015ccebbe757d24ea60ed2a
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.3.0"
|
||||||
|
google_sign_in_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: google_sign_in_android
|
||||||
|
sha256: d5e23c56a4b84b6427552f1cf3f98f716db3b1d1a647f16b96dbb5b93afa2805
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.2.1"
|
||||||
|
google_sign_in_ios:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: google_sign_in_ios
|
||||||
|
sha256: "102005f498ce18442e7158f6791033bbc15ad2dcc0afa4cf4752e2722a516c96"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.9.0"
|
||||||
|
google_sign_in_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: google_sign_in_platform_interface
|
||||||
|
sha256: "5f6f79cf139c197261adb6ac024577518ae48fdff8e53205c5373b5f6430a8aa"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.5.0"
|
||||||
|
google_sign_in_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: google_sign_in_web
|
||||||
|
sha256: "460547beb4962b7623ac0fb8122d6b8268c951cf0b646dd150d60498430e4ded"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.12.4+4"
|
||||||
graphs:
|
graphs:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1269,6 +1349,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.2"
|
version: "1.0.2"
|
||||||
|
twitter_login:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: twitter_login
|
||||||
|
sha256: "31ff9db2e37eda878b876a4ce6d1525f51d34b6cd9de9aa185b07027a23ab95b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.4.2"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -45,6 +45,11 @@ dependencies:
|
|||||||
firebase_messaging: ^15.2.4
|
firebase_messaging: ^15.2.4
|
||||||
flutter_local_notifications: ^18.0.1
|
flutter_local_notifications: ^18.0.1
|
||||||
|
|
||||||
|
# Social Login
|
||||||
|
google_sign_in: ^6.2.2
|
||||||
|
flutter_facebook_auth: ^7.1.1
|
||||||
|
twitter_login: ^4.4.2
|
||||||
|
|
||||||
# Pin to avoid objective_c crash on iOS 26 simulator
|
# Pin to avoid objective_c crash on iOS 26 simulator
|
||||||
path_provider_foundation: 2.4.0
|
path_provider_foundation: 2.4.0
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user