-
Notifications
You must be signed in to change notification settings - Fork 2
[FOSSOVERFLOW-26] migrate auth+login to supabase from firebase #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| { | ||
| "java.configuration.updateBuildConfiguration": "interactive", | ||
| "cmake.sourceDirectory": "C:/Users/akd24/Documents/GetWelPlus/flutter_app/linux" | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,4 +1,7 @@ | ||||||||||||||||||||||||||||||||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android"> | ||||||||||||||||||||||||||||||||||
| <uses-permission android:name="android.permission.INTERNET" /> | ||||||||||||||||||||||||||||||||||
| <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| <application | ||||||||||||||||||||||||||||||||||
| android:label="GetWel+" | ||||||||||||||||||||||||||||||||||
| android:name="${applicationName}" | ||||||||||||||||||||||||||||||||||
|
|
@@ -24,6 +27,17 @@ | |||||||||||||||||||||||||||||||||
| <action android:name="android.intent.action.MAIN"/> | ||||||||||||||||||||||||||||||||||
| <category android:name="android.intent.category.LAUNCHER"/> | ||||||||||||||||||||||||||||||||||
| </intent-filter> | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| <!-- Deep Links for Supabase Auth Callback --> | ||||||||||||||||||||||||||||||||||
| <intent-filter android:autoVerify="true"> | ||||||||||||||||||||||||||||||||||
| <action android:name="android.intent.action.VIEW" /> | ||||||||||||||||||||||||||||||||||
| <category android:name="android.intent.category.DEFAULT" /> | ||||||||||||||||||||||||||||||||||
| <category android:name="android.intent.category.BROWSABLE" /> | ||||||||||||||||||||||||||||||||||
| <!-- Replace with your actual deep link scheme --> | ||||||||||||||||||||||||||||||||||
| <data | ||||||||||||||||||||||||||||||||||
| android:scheme="io.supabase.getwelplus" | ||||||||||||||||||||||||||||||||||
| android:host="login-callback" /> | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+32
to
+39
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result:
What to do instead
Common setup pattern (recommended)
Two minor issues with the deep link intent-filter.
Proposed fix- <intent-filter android:autoVerify="true">
+ <intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
- <!-- Replace with your actual deep link scheme -->
<data
android:scheme="io.supabase.getwelplus"
android:host="login-callback" />
</intent-filter>📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
| </intent-filter> | ||||||||||||||||||||||||||||||||||
| </activity> | ||||||||||||||||||||||||||||||||||
| <!-- Don't delete the meta-data below. | ||||||||||||||||||||||||||||||||||
| This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> | ||||||||||||||||||||||||||||||||||
|
|
@@ -41,5 +55,13 @@ | |||||||||||||||||||||||||||||||||
| <action android:name="android.intent.action.PROCESS_TEXT"/> | ||||||||||||||||||||||||||||||||||
| <data android:mimeType="text/plain"/> | ||||||||||||||||||||||||||||||||||
| </intent> | ||||||||||||||||||||||||||||||||||
| <!-- Required for OAuth and opening browser --> | ||||||||||||||||||||||||||||||||||
| <intent> | ||||||||||||||||||||||||||||||||||
| <action android:name="android.intent.action.VIEW" /> | ||||||||||||||||||||||||||||||||||
| <category android:name="android.intent.category.BROWSABLE" /> | ||||||||||||||||||||||||||||||||||
| <data android:scheme="https" /> | ||||||||||||||||||||||||||||||||||
| </intent> | ||||||||||||||||||||||||||||||||||
| <!-- Required for Google Sign-In --> | ||||||||||||||||||||||||||||||||||
| <package android:name="com.google.android.gms" /> | ||||||||||||||||||||||||||||||||||
| </queries> | ||||||||||||||||||||||||||||||||||
| </manifest> | ||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| <?xml version="1.0" encoding="utf-8"?> | ||
| <network-security-config> | ||
| <base-config cleartextTrafficPermitted="false"> | ||
| <trust-anchors> | ||
| <certificates src="system" /> | ||
| <certificates src="user" /> | ||
| </trust-anchors> | ||
| </base-config> | ||
|
Comment on lines
+3
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Trusting user-installed certificates in production is a security risk. Including 🔒 Proposed fix: restrict user certs to debug builds <network-security-config>
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<certificates src="system" />
- <certificates src="user" />
</trust-anchors>
</base-config>
- <!-- Allow connections to Supabase in debug mode -->
- <domain-config cleartextTrafficPermitted="false">
- <domain includeSubdomains="true">supabase.co</domain>
- <trust-anchors>
- <certificates src="system" />
- <certificates src="user" />
- </trust-anchors>
- </domain-config>
+ <debug-overrides>
+ <trust-anchors>
+ <certificates src="user" />
+ </trust-anchors>
+ </debug-overrides>
</network-security-config>🤖 Prompt for AI Agents |
||
| <!-- Allow connections to Supabase in debug mode --> | ||
| <domain-config cleartextTrafficPermitted="false"> | ||
| <domain includeSubdomains="true">supabase.co</domain> | ||
| <trust-anchors> | ||
| <certificates src="system" /> | ||
| <certificates src="user" /> | ||
| </trust-anchors> | ||
| </domain-config> | ||
|
Comment on lines
+9
to
+16
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Redundant domain-config — identical to base-config. This 🤖 Prompt for AI Agents |
||
| </network-security-config> | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,13 +1,18 @@ | ||||||||||||||||||||||
| import 'package:flutter_riverpod/flutter_riverpod.dart'; | ||||||||||||||||||||||
| import 'package:firebase_auth/firebase_auth.dart'; | ||||||||||||||||||||||
| import 'package:supabase_flutter/supabase_flutter.dart'; | ||||||||||||||||||||||
| import 'auth_service.dart'; | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // Give app access to AuthService | ||||||||||||||||||||||
| // Provide access to AuthService | ||||||||||||||||||||||
| final authServiceProvider = Provider<AuthService>((ref) { | ||||||||||||||||||||||
| return AuthService(); | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // Listen to Firebase auth state | ||||||||||||||||||||||
| final authStateProvider = StreamProvider<User?>((ref) { | ||||||||||||||||||||||
| return ref.read(authServiceProvider).authstatechanges; | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
| // Listen to Supabase auth state changes | ||||||||||||||||||||||
| final authStateProvider = StreamProvider<AuthState>((ref) { | ||||||||||||||||||||||
| return ref.read(authServiceProvider).authStateChanges; | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // Get current user | ||||||||||||||||||||||
| final currentUserProvider = Provider<User?>((ref) { | ||||||||||||||||||||||
| return ref.read(authServiceProvider).currentUser; | ||||||||||||||||||||||
| }); | ||||||||||||||||||||||
|
Comment on lines
+15
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
To make it reactive, derive it from the auth state stream: Proposed fix-// Get current user
-final currentUserProvider = Provider<User?>((ref) {
- return ref.read(authServiceProvider).currentUser;
-});
+// Get current user (reactive)
+final currentUserProvider = Provider<User?>((ref) {
+ // Watch the auth state so this provider rebuilds on auth changes
+ ref.watch(authStateProvider);
+ return ref.read(authServiceProvider).currentUser;
+});📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,32 +1,160 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import 'package:firebase_auth/firebase_auth.dart'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import 'package:supabase_flutter/supabase_flutter.dart'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| import 'package:google_sign_in/google_sign_in.dart'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| class AuthService { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| final SupabaseClient _supabase = Supabase.instance.client; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Get current user | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| User? get currentUser => _supabase.auth.currentUser; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| class AuthService { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Listen to auth state changes | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Stream<AuthState> get authStateChanges => _supabase.auth.onAuthStateChange; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Check if user is logged in | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| bool get isLoggedIn => currentUser != null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| final FirebaseAuth firebaseAuth = FirebaseAuth.instance; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| User? get currentuser => firebaseAuth.currentUser; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Sign up with email and password | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Future<AuthResponse> signUp({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| required String email, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| required String password, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| required String name, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) async { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| final response = await _supabase.auth.signUp( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| email: email, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| password: password, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| data: {'name': name}, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| Stream<User?> get authstatechanges => firebaseAuth.authStateChanges(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (response.user != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| await _supabase.from('users').insert({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'id': response.user!.id, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'email': email, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'name': name, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'created_at': DateTime.now().toIso8601String(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (dbError) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // User already created in auth, profile creation can be retried later | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+29
to
+39
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: find . -name "auth_service.dart" -type fRepository: OpenLake/GetWelPlus Length of output: 103 🏁 Script executed: git ls-files flutter_app/lib/auth/ 2>/dev/null || find flutter_app/lib/auth -type f 2>/dev/null || trueRepository: OpenLake/GetWelPlus Length of output: 255 🏁 Script executed: head -50 ./flutter_app/lib/auth/auth_service.dart | tail -30Repository: OpenLake/GetWelPlus Length of output: 781 🌐 Web query:
💡 Result: In Supabase Flutter / Dart, a unique constraint (duplicate key) violation comes back as a
Example handling: try {
await supabase.from('users').insert({'email': email});
} on PostgrestException catch (e) {
if (e.code == '23505') {
// Unique constraint violation (duplicate key)
// e.details often contains which key/constraint conflicted
// Handle gracefully (show "already exists", etc.)
} else {
rethrow;
}
}Sources: [1] [2] 🏁 Script executed: rg "getUserProfile" flutter_app/lib/ -A 5Repository: OpenLake/GetWelPlus Length of output: 900 🏁 Script executed: rg "HomePage" flutter_app/lib/ -lRepository: OpenLake/GetWelPlus Length of output: 137 🏁 Script executed: rg "Future<Map<String, dynamic>\?> getUserProfile" flutter_app/lib/auth/auth_service.dart -A 15Repository: OpenLake/GetWelPlus Length of output: 435 🏁 Script executed: rg "userProfile" flutter_app/lib/pages/homepage.dart -B 2 -A 2Repository: OpenLake/GetWelPlus Length of output: 551 Silent error swallowing in profile creation—distinguish between duplicate and other failures. The current code silently catches all Handle specific errors correctly: Proposed fix if (response.user != null) {
try {
await _supabase.from('users').insert({
'id': response.user!.id,
'email': email,
'name': name,
'created_at': DateTime.now().toIso8601String(),
});
- } catch (dbError) {
- // User already created in auth, profile creation can be retried later
+ } on PostgrestException catch (dbError) {
+ // 23505 = unique_violation — safe to ignore (profile exists)
+ if (dbError.code != '23505') {
+ rethrow;
+ }
}
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| Future<UserCredential> login({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return response; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| rethrow; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Sign in with email and password | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Future<AuthResponse> signIn({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| required String email, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| required String password, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) async { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return await _supabase.auth.signInWithPassword( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| email: email, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| password: password, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| rethrow; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Sign in with Google | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Future<bool> signInWithGoogle() async { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| const webClientId = | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| '632491342639-mq70dmjhr8udmps5t312gkcrc5d90a17.apps.googleusercontent.com'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+64
to
+67
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hard-coded Google OAuth client ID in source code. The 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) async{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return await firebaseAuth.signInWithEmailAndPassword(email: email, password: password); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| final GoogleSignIn googleSignIn = GoogleSignIn( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| serverClientId: webClientId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| scopes: ['email', 'profile'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| final googleUser = await googleSignIn.signIn(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (googleUser == null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| final googleAuth = await googleUser.authentication; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| final accessToken = googleAuth.accessToken; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| final idToken = googleAuth.idToken; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (accessToken == null || idToken == null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| throw 'Google authentication tokens not found'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+83
to
+85
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Throwing a raw
- throw 'Google authentication tokens not found';
+ throw AuthException('Google authentication tokens not found');📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| final response = await _supabase.auth.signInWithIdToken( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| provider: OAuthProvider.google, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| idToken: idToken, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| accessToken: accessToken, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Create user profile if it doesn't exist | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (response.user != null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| final existingUser = await _supabase | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .from('users') | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .select() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .eq('id', response.user!.id) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .maybeSingle(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (existingUser == null) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| await _supabase.from('users').insert({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'id': response.user!.id, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'email': response.user!.email, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'name': googleUser.displayName ?? 'User', | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'created_at': DateTime.now().toIso8601String(), | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| return true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| rethrow; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| Future<UserCredential> signup({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| required String email, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| required String password, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) async{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return await firebaseAuth.createUserWithEmailAndPassword(email: email, password: password); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Sign out | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Future<void> signOut() async { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| await _supabase.auth.signOut(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| rethrow; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| Future<void> logout() async{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| await firebaseAuth.signOut(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Get user profile from database | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Future<Map<String, dynamic>?> getUserProfile(String userId) async { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| final response = await _supabase | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .from('users') | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .select() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .eq('id', userId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| .maybeSingle(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| return response; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| rethrow; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Update user profile | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Future<void> updateUserProfile({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| required String userId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| required Map<String, dynamic> data, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) async { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| await _supabase.from('users').update(data).eq('id', userId); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| rethrow; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Reset password | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Future<void> resetPassword(String email) async { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| await _supabase.auth.resetPasswordForEmail(email); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } catch (e) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| rethrow; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Misleading comment — this just uses Flutter's default
minSdkVersion.The comment "Required for Supabase" suggests a deliberate override, but
flutter.minSdkVersionis Flutter's default (currently 21). If Supabase requires a specific minimum SDK, hardcode it (e.g.,minSdk = 21). If not, remove the comment to avoid confusion.🤖 Prompt for AI Agents