Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .vscode/settings.json
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"
}
19 changes: 4 additions & 15 deletions flutter_app/android/app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
plugins {
id("com.android.application")
id("kotlin-android")
// Add the Google services Gradle plugin
id("com.google.gms.google-services")

// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id("dev.flutter.flutter-gradle-plugin")
}

Expand All @@ -27,10 +24,11 @@ android {
applicationId = "com.example.flutter_app"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
minSdk = flutter.minSdkVersion // Required for Supabase
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Misleading comment — this just uses Flutter's default minSdkVersion.

The comment "Required for Supabase" suggests a deliberate override, but flutter.minSdkVersion is 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
In `@flutter_app/android/app/build.gradle.kts` at line 27, The comment next to the
minSdk assignment is misleading because minSdk is set from flutter.minSdkVersion
(the Flutter default) rather than an explicit Supabase requirement; either
hardcode the required minimum (e.g., set minSdk = 21) if Supabase demands a
specific SDK level, or keep flutter.minSdkVersion and remove the "Required for
Supabase" comment to avoid confusion — update the minSdk line and/or comment
accordingly in the build file where minSdk and flutter.minSdkVersion are
referenced.

targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
multiDexEnabled = true // Required for apps with many dependencies
}

buildTypes {
Expand All @@ -47,15 +45,6 @@ flutter {
}

dependencies {
// Import the Firebase BoM
implementation(platform("com.google.firebase:firebase-bom:34.8.0"))


// TODO: Add the dependencies for Firebase products you want to use
// When using the BoM, don't specify versions in Firebase dependencies
implementation("com.google.firebase:firebase-analytics")


// Add the dependencies for any other desired Firebase products
// https://firebase.google.com/docs/android/setup#available-libraries
implementation("com.google.android.gms:play-services-auth:21.1.0")
implementation("androidx.multidex:multidex:2.0.1")
}
22 changes: 22 additions & 0 deletions flutter_app/android/app/src/main/AndroidManifest.xml
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}"
Expand All @@ -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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Android autoVerify custom URI schemes intent-filter

💡 Result:

android:autoVerify="true" does not work for custom URI schemes (e.g., myapp://...). Auto-verification is only for Android App Links, which are web URLs using http/https and are verified via a website-hosted Digital Asset Links file (/.well-known/assetlinks.json). Also, an intent-filter considered for verification must not declare any other schemes besides http/https. [1], [4], [5]

What to do instead

  • If you need “no chooser dialog” deep links: use HTTPS App Links with android:autoVerify="true" + assetlinks.json. [1], [4]
  • If you must use a custom scheme (myapp://): you can still declare it in an intent-filter, but it can’t be verified; if another app registers the same scheme, Android may show the chooser. [6]

Common setup pattern (recommended)

  • One intent-filter for verified links:
    • https://yourdomain/... with android:autoVerify="true" (and assetlinks.json). [1], [4]
  • A separate intent-filter for legacy/custom deep links:
    • myapp://... without expecting verification. [6]

Two minor issues with the deep link intent-filter.

  1. android:autoVerify="true" is ineffective with custom URI schemes. Auto-verification is an Android App Links feature that only works with http/https schemes and requires a /.well-known/assetlinks.json file on the verified domain. For the custom scheme io.supabase.getwelplus, this attribute is silently ignored. Remove it to avoid confusion.

  2. Line 36: Stale template comment. The comment <!-- Replace with your actual deep link scheme --> should be removed since the scheme is already configured.

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

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<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" />
<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="io.supabase.getwelplus"
android:host="login-callback" />
</intent-filter>
🤖 Prompt for AI Agents
In `@flutter_app/android/app/src/main/AndroidManifest.xml` around lines 32 - 39,
Remove the ineffective android:autoVerify="true" attribute from the
<intent-filter> (autoVerify only applies to http/https App Links) and delete the
stale comment "<!-- Replace with your actual deep link scheme -->" since the
scheme is already set (android:scheme="io.supabase.getwelplus" and
android:host="login-callback"); keep the intent-filter and <data> element as-is
so the custom URI scheme continues to work.

</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
Expand All @@ -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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Trusting user-installed certificates in production is a security risk.

Including <certificates src="user" /> in <base-config> means release builds will trust user-installed CA certificates, re-enabling MITM proxy attacks that Android 7+ (API 24) disabled by default. User CA trust should be limited to debug builds via <debug-overrides>.

🔒 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
In `@flutter_app/android/app/src/main/res/xml/network_security_config.xml` around
lines 3 - 8, The network_security_config currently trusts user-installed CAs in
production by including <certificates src="user" /> inside the base-config;
remove or relocate that entry so release builds do not trust user CAs and
instead add a <debug-overrides> section that contains <trust-anchors> with
<certificates src="user" /> for debugging only (use the existing base-config for
system certs only). Update the network_security_config.xml to keep <base-config
cleartextTrafficPermitted="false"> with only <certificates src="system" /> and
move <certificates src="user" /> under a <debug-overrides> block to ensure user
CA trust is limited to debug builds.

<!-- 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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Redundant domain-config — identical to base-config.

This <domain-config> block has the same cleartextTrafficPermitted="false" and the same trust anchors as the <base-config>, so it has no effect. The comment mentions "debug mode," but nothing here is debug-specific. The proposed fix above removes this block and moves user-cert trust into <debug-overrides> where it belongs.

🤖 Prompt for AI Agents
In `@flutter_app/android/app/src/main/res/xml/network_security_config.xml` around
lines 9 - 16, Remove the redundant <domain-config> block that duplicates the
<base-config> (same cleartextTrafficPermitted and identical trust-anchors) so it
has no effect; instead, move user certificate trust (certificates src="user")
into the <debug-overrides> section so user-added certs are only allowed in debug
mode and keep the base-config with system certs only, updating the
network_security_config.xml elements <base-config>, <debug-overrides>, and any
existing <domain-config> entries (e.g., the supabase.co domain-config)
accordingly.

</network-security-config>
4 changes: 0 additions & 4 deletions flutter_app/android/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
plugins {
// ...

// Add the dependency for the Google services Gradle plugin
id("com.google.gms.google-services") version "4.4.4" apply false

}
allprojects {
repositories {
Expand Down
17 changes: 11 additions & 6 deletions flutter_app/lib/auth/auth_provider.dart
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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

currentUserProvider is not reactive — it returns a stale snapshot.

ref.read(authServiceProvider).currentUser captures the user at provider-creation time and never updates. After login or logout, consumers of this provider will still see the old value.

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

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// 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;
});
🤖 Prompt for AI Agents
In `@flutter_app/lib/auth/auth_provider.dart` around lines 15 - 18,
currentUserProvider currently reads a snapshot
(ref.read(authServiceProvider).currentUser) and never updates; change it to
derive from the AuthService's reactive auth-state stream by using a
StreamProvider (or Provider that ref.watch(...)s the service's stream) instead
of ref.read, e.g., have currentUserProvider subscribe to the AuthService's
stream property (authStateStream / authStateChanges / currentUserStream) so it
emits updated User? values on login/logout; update references to
currentUserProvider accordingly.

160 changes: 144 additions & 16 deletions flutter_app/lib/auth/auth_service.dart
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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -name "auth_service.dart" -type f

Repository: 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 || true

Repository: OpenLake/GetWelPlus

Length of output: 255


🏁 Script executed:

head -50 ./flutter_app/lib/auth/auth_service.dart | tail -30

Repository: OpenLake/GetWelPlus

Length of output: 781


🌐 Web query:

Supabase Flutter PostgrestException error codes unique constraint violation

💡 Result:

In Supabase Flutter / Dart, a unique constraint (duplicate key) violation comes back as a PostgrestException where:

  • e.code == '23505' (Postgres SQLSTATE for uniqueness violation) and the REST API typically maps it to HTTP 409 Conflict. [1]
  • The exception also carries message, details, and hint fields you can display/log. [2]

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 5

Repository: OpenLake/GetWelPlus

Length of output: 900


🏁 Script executed:

rg "HomePage" flutter_app/lib/ -l

Repository: OpenLake/GetWelPlus

Length of output: 137


🏁 Script executed:

rg "Future<Map<String, dynamic>\?> getUserProfile" flutter_app/lib/auth/auth_service.dart -A 15

Repository: OpenLake/GetWelPlus

Length of output: 435


🏁 Script executed:

rg "userProfile" flutter_app/lib/pages/homepage.dart -B 2 -A 2

Repository: OpenLake/GetWelPlus

Length of output: 551


Silent error swallowing in profile creation—distinguish between duplicate and other failures.

The current code silently catches all PostgrestException errors when inserting a user profile. If the insert fails for reasons other than a duplicate key (e.g., RLS policy misconfiguration, network failure, schema mismatch), the user is created in Supabase Auth but has no profile row. Downstream code like HomePage, which calls getUserProfile(), will silently show incomplete data (e.g., userProfile?['name'] returns null and falls back to a generic "User" label) with no visibility into what went wrong. This makes debugging and recovery impossible.

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

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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
}
if (response.user != null) {
try {
await _supabase.from('users').insert({
'id': response.user!.id,
'email': email,
'name': name,
'created_at': DateTime.now().toIso8601String(),
});
} on PostgrestException catch (dbError) {
// 23505 = unique_violation — safe to ignore (profile exists)
if (dbError.code != '23505') {
rethrow;
}
}
🤖 Prompt for AI Agents
In `@flutter_app/lib/auth/auth_service.dart` around lines 29 - 39, The profile
insertion currently swallows all errors in the try/catch around
_supabase.from('users').insert(...); change the catch to handle
PostgrestException specifically: if the error indicates a duplicate key (unique
constraint violation) then ignore/return, otherwise log the full error (or
rethrow) so calling code can detect failed profile creation; ensure you
reference the insert call on _supabase and the caught PostgrestException
(dbError) so the fix is applied in the same method that inserts the user
profile.

}

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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Hard-coded Google OAuth client ID in source code.

The webClientId is a sensitive configuration value committed directly to the repository. While OAuth client IDs are not strictly secret, embedding them here ties the app to a single environment and makes rotation harder. Move this to an environment-level configuration (e.g., --dart-define, a .env file loaded at runtime, or Supabase's dashboard-configured OAuth provider).

🤖 Prompt for AI Agents
In `@flutter_app/lib/auth/auth_service.dart` around lines 64 - 67, The hard-coded
OAuth client ID in signInWithGoogle (the webClientId constant) should be moved
to an environment-level configuration and loaded at runtime; replace the inline
string with a call that reads from your chosen config source (e.g., Dart
compile-time defines via String.fromEnvironment, a runtime .env loader like
flutter_dotenv, or your backend/Supabase-configured OAuth value) and update
signInWithGoogle to use that config value and fail-fast with a clear error if
the env value is missing; ensure you document the required env key and remove
the literal from source control.


}) 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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Throwing a raw String instead of a typed exception.

throw 'Google authentication tokens not found' produces a String, which won't be caught by on AuthException catch (e) in the calling code (login_page.dart line 78). It falls through to the generic catch (e) block, hiding the specific message. Throw an AuthException instead:

-      throw 'Google authentication tokens not found';
+      throw AuthException('Google authentication tokens not found');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (accessToken == null || idToken == null) {
throw 'Google authentication tokens not found';
}
if (accessToken == null || idToken == null) {
throw AuthException('Google authentication tokens not found');
}
🤖 Prompt for AI Agents
In `@flutter_app/lib/auth/auth_service.dart` around lines 83 - 85, Replace the raw
string throw with a typed AuthException so callers using "on AuthException catch
(e)" can handle it: in auth_service.dart (inside the code path that checks
accessToken and idToken) throw an AuthException with a clear message (e.g.,
"Google authentication tokens not found") instead of throwing a String; ensure
you import or reference the AuthException class used by login_page.dart and
preserve the original message when constructing the exception.


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;
}
}
}
11 changes: 7 additions & 4 deletions flutter_app/lib/auth/auth_wrapper.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:flutter_app/pages/homepage.dart';
import 'login_page.dart';
import 'signup_page.dart';
Expand All @@ -16,8 +16,8 @@ class _AuthWrapperState extends State<AuthWrapper> {

@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
return StreamBuilder<AuthState>(
stream: Supabase.instance.client.auth.onAuthStateChange,
builder: (context, snapshot) {
// Loading
if (snapshot.connectionState == ConnectionState.waiting) {
Expand All @@ -26,8 +26,11 @@ class _AuthWrapperState extends State<AuthWrapper> {
);
}

// Check if user is logged in
final session = snapshot.hasData ? snapshot.data!.session : null;

// Logged in
if (snapshot.hasData) {
if (session != null) {
return const HomePage();
}

Expand Down
Loading