-
Notifications
You must be signed in to change notification settings - Fork 28
Fix/upgrade dependencies google sign #143
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
671ef15
6871fca
1da5488
efb3b9b
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 |
|---|---|---|
|
|
@@ -83,7 +83,7 @@ class AuthProvider extends ChangeNotifier { | |
|
|
||
| Future<void> _handleWebSignIn() async { | ||
| final supabaseUrl = dotenv.env['SUPABASE_URL'] ?? | ||
| (throw Exception("Supabase URL not found in .env")); | ||
| (throw Exception("Supabase URL not found in .env")); | ||
|
|
||
| await supabase.auth.signInWithOAuth( | ||
| OAuthProvider.google, | ||
|
|
@@ -93,29 +93,44 @@ class AuthProvider extends ChangeNotifier { | |
| } | ||
|
|
||
| Future<void> _handleMobileSignIn() async { | ||
| final webClientId = dotenv.env['GOOGLE_WEB_CLIENT_ID'] ?? | ||
| (throw Exception("WEB_CLIENT_ID not found in .env")); | ||
| final webClientId = dotenv.env['GOOGLE_WEB_CLIENT_ID'] ?? | ||
| (throw Exception("WEB_CLIENT_ID not found in .env")); | ||
| final iosClientId = dotenv.env['GOOGLE_IOS_CLIENT_ID']; | ||
|
|
||
| final GoogleSignIn googleSignIn = GoogleSignIn( | ||
|
|
||
| // Get the singleton instance. | ||
| final GoogleSignIn googleSignIn = GoogleSignIn.instance; | ||
|
|
||
| // Initialize the GoogleSignIn instance. | ||
| await googleSignIn.initialize( | ||
| clientId: Platform.isIOS ? iosClientId : null, | ||
| serverClientId: webClientId, | ||
| scopes: ['email', 'profile'], | ||
| ); | ||
|
|
||
| final GoogleSignInAccount? googleUser = await googleSignIn.signIn(); | ||
| if (googleUser == null) throw 'Sign in cancelled'; | ||
| // Define scopes (they were moved from the constructor/initialize to the sign-in call). | ||
| const List<String> scopes = ['email', 'profile']; | ||
|
|
||
| final GoogleSignInAuthentication googleAuth = | ||
| await googleUser.authentication; | ||
| // Sign-in logic | ||
| final GoogleSignInAccount? googleUser = await googleSignIn.authenticate( | ||
| scopeHint: scopes, | ||
| ); | ||
| if (googleUser == null) throw 'Sign in cancelled'; | ||
|
|
||
| if (googleAuth.idToken == null) throw 'No ID Token found'; | ||
| if (googleAuth.accessToken == null) throw 'No Access Token found'; | ||
| // Authorization to get access token | ||
| final authorization = await googleUser.authorizationClient.authorizeScopes( | ||
| scopes | ||
| ); | ||
| final String accessToken = authorization.accessToken; | ||
|
|
||
| // Authentication (It now synchronous as per v7.0+). | ||
| final GoogleSignInAuthentication googleAuth = googleUser.authentication; | ||
| final String? idToken = googleAuth.idToken; | ||
| if (idToken == null) throw 'No ID Token found'; | ||
|
|
||
| // Supabase login (now with the retrieved accessToken) | ||
| await supabase.auth.signInWithIdToken( | ||
| provider: OAuthProvider.google, | ||
| idToken: googleAuth.idToken!, | ||
| accessToken: googleAuth.accessToken, | ||
| idToken: idToken, | ||
| accessToken: accessToken, | ||
| ); | ||
| } | ||
|
Comment on lines
95
to
135
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 Significant code duplication with therapist authentication. The Create a shared authentication helper: // In a shared package or common directory
class GoogleSignInHelper {
static Future<({String idToken, String accessToken})> signInMobile({
required String webClientId,
String? iosClientId,
}) async {
final GoogleSignIn googleSignIn = GoogleSignIn.instance;
await googleSignIn.initialize(
clientId: Platform.isIOS ? iosClientId : null,
serverClientId: webClientId,
);
const List<String> scopes = ['email', 'profile'];
final GoogleSignInAccount? googleUser = await googleSignIn.authenticate(
scopeHint: scopes,
);
if (googleUser == null) throw Exception('Sign in cancelled');
final authorization = await googleUser.authorizationClient.authorizeScopes(scopes);
final String accessToken = authorization.accessToken;
final GoogleSignInAuthentication googleAuth = googleUser.authentication;
final String? idToken = googleAuth.idToken;
if (idToken == null) throw Exception('No ID Token found');
return (idToken: idToken, accessToken: accessToken);
}
}Then use it in both files: Future<void> _handleMobileSignIn() async {
final webClientId = dotenv.env['GOOGLE_WEB_CLIENT_ID'] ??
(throw Exception("WEB_CLIENT_ID not found in .env"));
final iosClientId = dotenv.env['GOOGLE_IOS_CLIENT_ID'];
final tokens = await GoogleSignInHelper.signInMobile(
webClientId: webClientId,
iosClientId: iosClientId,
);
await supabase.auth.signInWithIdToken(
provider: OAuthProvider.google,
idToken: tokens.idToken,
accessToken: tokens.accessToken,
);
} |
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -74,29 +74,44 @@ class SupabaseAuthRepository implements AuthRepository { | |
| } | ||
|
|
||
| Future<void> _handleMobileSignIn() async { | ||
| final webClientId = dotenv.env['GOOGLE_WEB_CLIENT_ID'] ?? | ||
| (throw Exception("WEB_CLIENT_ID not found in .env")); | ||
| final webClientId = dotenv.env['GOOGLE_WEB_CLIENT_ID'] ?? | ||
| (throw Exception("WEB_CLIENT_ID not found in .env")); | ||
| final iosClientId = dotenv.env['GOOGLE_IOS_CLIENT_ID']; | ||
|
|
||
| final GoogleSignIn googleSignIn = GoogleSignIn( | ||
|
|
||
| // Get the singleton instance. | ||
| final GoogleSignIn googleSignIn = GoogleSignIn.instance; | ||
|
|
||
| // Initialize the GoogleSignIn instance. | ||
| await googleSignIn.initialize( | ||
| clientId: Platform.isIOS ? iosClientId : null, | ||
| serverClientId: webClientId, | ||
| scopes: ['email', 'profile'], | ||
| ); | ||
|
|
||
| final GoogleSignInAccount? googleUser = await googleSignIn.signIn(); | ||
| // Define scopes (they were moved from the constructor/initialize to the sign-in call). | ||
| const List<String> scopes = ['email', 'profile']; | ||
|
|
||
| // Sign-in logic | ||
| final GoogleSignInAccount? googleUser = await googleSignIn.authenticate( | ||
| scopeHint: scopes, | ||
| ); | ||
| if (googleUser == null) throw 'Sign in cancelled'; | ||
|
|
||
| final GoogleSignInAuthentication googleAuth = | ||
| await googleUser.authentication; | ||
| // Authorization to get access token | ||
| final authorization = await googleUser.authorizationClient.authorizeScopes( | ||
| scopes | ||
| ); | ||
| final String accessToken = authorization.accessToken; | ||
|
|
||
| if (googleAuth.idToken == null) throw 'No ID Token found'; | ||
| if (googleAuth.accessToken == null) throw 'No Access Token found'; | ||
| // Authentication (It now synchronous as per v7.0+). | ||
| final GoogleSignInAuthentication googleAuth = googleUser.authentication; | ||
| final String? idToken = googleAuth.idToken; | ||
| if (idToken == null) throw 'No ID Token found'; | ||
|
|
||
| // Supabase login (now with the retrieved accessToken) | ||
| await _supabaseClient.auth.signInWithIdToken( | ||
| provider: OAuthProvider.google, | ||
| idToken: googleAuth.idToken!, | ||
| accessToken: googleAuth.accessToken, | ||
| idToken: idToken, | ||
| accessToken: accessToken, | ||
| ); | ||
| } | ||
|
Comment on lines
76
to
116
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 π§© Analysis chainSame Google Sign-In v7 concerns as patient app. This mobile sign-in implementation is identical to
The suggestion to extract shared authentication logic into a common utility would eliminate this duplication and ensure consistent behavior. See the detailed refactor suggestion in the review of π Script executed: #!/bin/bash
# Locate and display the patient app auth provider file
echo "=== Checking patient app auth file ==="
fd "auth_provider.dart" --type f 2>/dev/null | head -20
echo -e "\n=== Displaying patient/lib/provider/auth_provider.dart (lines 95-135) ==="
if [ -f "patient/lib/provider/auth_provider.dart" ]; then
sed -n '95,135p' "patient/lib/provider/auth_provider.dart"
else
echo "File not found at patient/lib/provider/auth_provider.dart"
fi
echo -e "\n=== Searching for other sign-in implementations ==="
rg -n "authenticate\s*\(" --type dart -B2 -A2 | head -50Length of output: 2510 π Script executed: #!/bin/bash
# Search for OAuth/GoogleSignIn patterns to identify code duplication
echo "=== Searching for GoogleSignIn.authenticate patterns ==="
rg -n "GoogleSignIn.*authenticate|googleSignIn\.authenticate" --type dart -B3 -A3
echo -e "\n=== Searching for authorizeScopes patterns ==="
rg -n "authorizeScopes" --type dart -B2 -A2
echo -e "\n=== Searching for shared auth utilities ==="
fd "auth" --type d | grep -i util
fd "auth" --type f -path "*/shared/*" -o -path "*/common/*" | head -20Length of output: 2319 π Script executed: #!/bin/bash
# Check exception handling patterns
echo "=== String exceptions in sign-in methods ==="
rg -n "throw\s+['\"].*['\"]" --type dart -B2 -A1 | grep -i "sign\|auth" | head -30
echo -e "\n=== Comparing file structures ==="
echo "Therapist file:"
wc -l therapist/lib/repository/supabase_auth_repository.dart 2>/dev/null || echo "Not found"
echo -e "\nPatient file:"
wc -l patient/lib/provider/auth_provider.dart 2>/dev/null || echo "Not found"Length of output: 1575 Extract shared Google Sign-In v7 authentication logic into a common utility to eliminate duplication and standardize exception handling. Code duplication confirmed: both patient ( π€ Prompt for AI Agents |
||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,7 +30,7 @@ environment: | |
| dependencies: | ||
| flutter: | ||
| sdk: flutter | ||
| easy_date_timeline: ^1.0.4 | ||
| easy_date_timeline: ^2.0.9 | ||
|
|
||
| # State Management | ||
| provider: ^6.1.2 | ||
|
|
@@ -42,25 +42,25 @@ dependencies: | |
| dart_mappable: ^4.4.0 | ||
| google_fonts: ^6.1.0 | ||
| flutter_native_splash: ^2.3.6 | ||
| google_sign_in: ^6.1.6 | ||
| google_sign_in: ^7.2.0 | ||
| flutter_svg: ^2.0.9 | ||
| smooth_page_indicator: ^1.1.0 | ||
|
|
||
| # intl | ||
| intl: ^0.19.0 | ||
| intl: ^0.20.2 | ||
|
|
||
| # The following adds the Cupertino Icons font to your application. | ||
| # Use with the CupertinoIcons class for iOS style icons. | ||
| cupertino_icons: ^1.0.6 | ||
| flutter_dotenv: ^5.2.1 | ||
| dotted_border: ^2.1.0 | ||
| flutter_dotenv: ^6.0.0 | ||
| dotted_border: ^3.1.0 | ||
| uuid: ^4.5.1 | ||
| flutter_gemini: ^3.0.0 | ||
| get_it: ^8.2.0 | ||
| get_it: ^9.0.5 | ||
|
|
||
| # Voice features | ||
| speech_to_text: ^6.6.0 | ||
| flutter_tts: ^3.8.5 | ||
| speech_to_text: ^7.3.0 | ||
|
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 chainExcellent: speech_to_text upgraded beyond target version. The issue #142 targeted speech_to_text ^6.x.x, but this PR upgrades to ^7.3.0, which is even better as it includes more recent bug fixes and improvements. Ensure the upgrade doesn't introduce breaking changes in the speech recognition functionality. π Web query: π‘ Result: Here are the key breaking / migration points for speech_to_text >= 7.0 and what to change (short checklist + minimal code examples). Summary of changes
What to do when upgrading to 7.x
Useful references (read these while migrating)
References If you want I can:
I need to verify how π Script executed: #!/bin/bash
# Search for speech_to_text imports and usage in the therapist app
rg -n "speech_to_text|SpeechToText" --type dart -C 3Length of output: 994 π Script executed: #!/bin/bash
# Search specifically for listen() calls which may need migration
rg -nP "\.listen\s*\(" --type dart -C 5Length of output: 4576 π Script executed: #!/bin/bash
# Check for SpeechListenOptions (v7.0 new parameter structure)
rg "SpeechListenOptions" --type dartLength of output: 0 π Script executed: #!/bin/bash
# Check Android embedding version in MainActivity
fd "MainActivity" --type f -x cat {}Length of output: 261 π Script executed: #!/bin/bash
# Check Android build configuration
fd "build.gradle" --type f | xargs catLength of output: 4554 π Script executed: #!/bin/bash
# Look for any explicit platform configurations
fd "pubspec.yaml" -x cat {}Length of output: 8820 π Script executed: #!/bin/bash
# Check if there are any deprecated listen() parameter usages
rg -nP "listen\s*\(\s*onResult|listen\s*\(\s*listenFor|listen\s*\(\s*localeId" --type dartLength of output: 0 π Script executed: #!/bin/bash
# Search for any web or macOS configuration files
fd -e "web" -e "macos" --type d -C 5Length of output: 230 π Script executed: #!/bin/bash
# Check for iOS and Android platform configurations
ls -la ios/ android/ macos/ web/ 2>/dev/null || echo "Checking available directories..."Length of output: 33 π Script executed: #!/bin/bash
# Get an overview of the project structure
find . -maxdepth 2 -type d -name "lib" -o -name "android" -o -name "ios" -o -name "macos" -o -name "web" | head -20Length of output: 161 π Script executed: #!/bin/bash
# Check for migration-related comments or TODOs in the code
rg -n "TODO|FIXME|migrate|breaking" --type dart -i | head -20Length of output: 1001 π Script executed: #!/bin/bash
# Get full pubspec.yaml to understand all dependencies and platform support
cat therapist/pubspec.yamlLength of output: 4452 π Script executed: #!/bin/bash
# Check if speech_to_text is actually used by searching pubspec files
rg "speech_to_text" --type yamlLength of output: 47 π Script executed: #!/bin/bash
# Look for platform-specific implementations
find . -path "*/lib/*" -name "*.dart" -type f | xargs rg -l "SpeechToText\|speech_to_text" 2>/dev/null | head -10Length of output: 0 π Script executed: #!/bin/bash
# Check for any listen method calls in detail
rg -nPA 15 "\.listen\(" --type dart | head -50Length of output: 4189 π Script executed: #!/bin/bash
# Verify Android embedding by checking MainActivity
find . -name "MainActivity.kt" -o -name "MainActivity.java" | xargs cat 2>/dev/nullLength of output: 261 π Script executed: #!/bin/bash
# Check gradle version and settings
find . -path "*/android/*" -name "*.gradle" | xargs head -30Length of output: 4119 π Script executed: #!/bin/bash
# Look for migration issues or platform-specific code
rg -n "onDevice|autoPunctuation|enableHapticFeedback|listenOptions" --type dartLength of output: 0 π Script executed: #!/bin/bash
# Check if macOS is supported
test -d "macos" && echo "macOS platform exists" || echo "macOS platform not found"
test -d "web" && echo "web platform exists" || echo "web platform not found"Length of output: 47 π Script executed: #!/bin/bash
# Final comprehensive check - list all Dart files that might use speech_to_text
find therapist/lib -name "*.dart" -type f 2>/dev/null | xargs grep -l "speech_to_text\|SpeechToText" 2>/dev/nullLength of output: 46 π Script executed: #!/bin/bash
# Check the actual listen() implementation for any parameter passing
rg -nA 20 "await.*\.listen\(" --type dartLength of output: 1679 π Script executed: #!/bin/bash
# Search for stop() and cancel() calls
rg -nP "\.stop\(\)|\.cancel\(\)" --type dart -C 2Length of output: 3199 π Script executed: #!/bin/bash
# Check for initialize() calls which might need verification
rg -nP "\.initialize\(" --type dart -C 3Length of output: 3641 π Script executed: #!/bin/bash
# Look for locale-related code
rg -n "localeId|locales\(\)" --type dart -C 2Length of output: 440 π Script executed: #!/bin/bash
# Examine version constraints in pubspec
cat therapist/pubspec.yaml | grep -A 2 -B 2 "speech_to_text"Length of output: 69 π Script executed: #!/bin/bash
# Final check - see if there's any existing migration discussion or PRs
git log --oneline --all | grep -i "speech\|upgrade\|migrate\|7\." | head -10Length of output: 57 π Script executed: #!/bin/bash
# Check git diff to see exactly what changed
git diff HEAD -- therapist/pubspec.yamlLength of output: 0 π Script executed: #!/bin/bash
# Verify the full context of the change
git show HEAD:therapist/pubspec.yaml | grep -A 1 -B 1 "speech_to_text" || echo "Previous version check failed"Length of output: 65 π Script executed: #!/bin/bash
# Look for any error handling or try-catch around speech recognition
rg -n "try\s*{|catch|Exception" --type dart -C 3 | grep -A 5 -B 5 "listen\|speech"Length of output: 112 π Script executed: #!/bin/bash
# Check if this is an existing project with established usage
test -f "therapist/pubspec.lock" && echo "Lock file exists" && head -50 therapist/pubspec.lock | grep -A 2 "speech_to_text"Length of output: 0 π Script executed: #!/bin/bash
# Simple check - does the code actually import and use speech_to_text?
rg -c "speech_to_text" therapist/lib/ therapist/pubspec.yaml 2>/dev/null || echo "No usage found"Length of output: 73 π Script executed: #!/bin/bash
# List all files in lib directory
ls -la therapist/lib/ 2>/dev/null || ls -la lib/ 2>/dev/null || find . -maxdepth 3 -type d -name "lib"Length of output: 466 π Script executed: #!/bin/bash
# Search broadly for any speech recognition code
rg -n "speech|recognize|listen" --type dart -i | head -30Length of output: 2175 Fix required: Migrate speech_to_text listen() call to v7.0+ API The upgrade introduces a breaking change in the listen() method signature. v6.6.0+ deprecated separate listen parameters in favor of a single SpeechListenOptions parameter. File: therapist/lib/core/services/voice_service.dart, lines 85β98 Replace the current listen() call with the new structure: await _speechToText.listen(
onResult: (result) {
if (result.finalResult) {
_speechController.add(result.recognizedWords);
}
},
listenOptions: SpeechListenOptions(
listenFor: const Duration(seconds: 30),
pauseFor: const Duration(seconds: 3),
partialResults: true,
localeId: "en_US",
onSoundLevelChange: (level) {
// Optional: Handle sound level changes
},
),
);Also verify the Android app uses V2 embedding (MainActivity extends FlutterActivity)βthis is already correct in your setup. π€ Prompt for AI Agents |
||
| flutter_tts: ^4.2.3 | ||
|
|
||
| dev_dependencies: | ||
| flutter_test: | ||
|
|
@@ -73,7 +73,7 @@ dev_dependencies: | |
| # activated in the `analysis_options.yaml` file located at the root of your | ||
| # package. See that file for information about deactivating specific lint | ||
| # rules and activating additional ones. | ||
| flutter_lints: ^3.0.0 | ||
| flutter_lints: ^6.0.0 | ||
|
|
||
| # For information on the generic Dart part of this file, see the | ||
| # following page: https://dart.dev/tools/pub/pubspec | ||
|
|
||
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.
π§© Analysis chain
Verify the Google Sign-In v7 authentication flow.
The migration to google_sign_in v7 uses
authenticate()withscopeHint, but this pattern should be verified against the official migration guide. In v7.0+, the typical flow is:signIn()was replaced byauthenticate()for initial sign-inauthorizeScopes()is typically used for incremental authorization (requesting additional scopes after initial sign-in)The current implementation calls both
authenticate()and then immediatelyauthorizeScopes(), which may be redundant. Please verify:authenticate()already returns tokens that can be accessed directlyscopeHintparameter is the correct API for passing scopes toauthenticate()authorizeScopes()is necessary immediately afterauthenticate()for the initial sign-in flowπ Web query:
π‘ Result:
Summary β what changed in google_sign_in v7.x
Quick migration steps (minimal)
Initialize once:
await GoogleSignIn.instance.initialize();. [1]
Lightweight / silent:
await GoogleSignIn.instance.attemptLightweightAuthentication(); // no UI if possible. [1]
User-initiated sign-in UI:
final GoogleSignInAccount account = await GoogleSignIn.instance.authenticate();
// may throw GoogleSignInException if cancelled. [1][4]
Request OAuth tokens (authorization) only after authentication:
// request scopes / tokens from the accountβs authorization client
final authorized = await account.authorizationClient.authorizeScopes(desiredScopes);
final accessToken = authorized.accessToken;
// Use authorized.idToken / serverAuthCode depending on platform and flow. [1][2]
Firebase / signInWithCredential:
Platform notes / gotchas
Minimal example
final account = await GoogleSignIn.instance.authenticate();
final authorized = await account.authorizationClient.authorizeScopes(['email','profile','https://www.googleapis.com/auth/drive.readonly']);
final accessToken = authorized.accessToken;
final idToken = authorized.idToken; // if provided for that flow
// Use tokens (e.g., Firebase credential, API calls).
Sources
[1] google_sign_in v7.0.0 package docs (migration + API examples).
[2] StackOverflow β example showing authenticate() then account.authorizationClient.authorizeScopes(...) to obtain accessToken.
[3] GitHub / flutter issues & plugin notes about signIn removal and web migration.
π Web query:
π‘ Result:
Short answer: in google_sign_in v7 the flows are separated β authenticate() (or signIn/signInSilently) performs authentication (who the user is) while authorizeScopes / authorizeServer perform OAuth authorization (granting scopes and returning an access token or server auth code). Use authenticate() to sign the user in and get profile/id info; call authorizeScopes(...) (or authorizeServer(...)) when you need accessToken or additional OAuth scopes (Drive, Gmail, backend server code exchange). [1][2][3]
Quick usage sketch:
Notes:
Sources:
Fix Google Sign-In v7 authentication flow to follow the official migration pattern.
In google_sign_in v7, authentication and authorization are separated:
authenticate()performs authentication (identity), whileauthorizeScopes()performs OAuth authorization (scopes/tokens). The current implementation has two issues:Incorrect
scopeHintparameter: Theauthenticate()method should not receive scopes; the correct flow is to callauthenticate()and then callaccount.authorizationClient.authorizeScopes(scopes)to obtain OAuth tokens.Missing authorization step: After authentication, you must call
account.authorizationClient.authorizeScopes(desiredScopes)to request OAuth tokens and scopes. This is required for accessing tokens, not redundant.Required fix: Remove
scopeHintfromauthenticate()and add the authorization step:π€ Prompt for AI Agents