connect static method

Future<GoogleDriveProvider?> connect({
  1. bool forceInteractive = false,
  2. List<String>? scopes,
  3. String? serverClientId,
  4. String? clientSecret,
  5. int redirectPort = 8000,
})
override

Connects to Google Drive, authenticating the user.

This method handles the Google Sign-In flow. It will attempt to sign in silently first, unless forceInteractive is true.

scopes a list of additional Google API scopes to request. The default scopes are drive.DriveApi.driveAppdataScope or drive.DriveApi.driveScope depending on MultiCloudStorage.cloudAccess. serverClientId The server client ID for requesting an ID token if you need to authenticate to a backend server.

Returns a connected GoogleDriveProvider instance on success, or null on failure/cancellation.

Implementation

static Future<GoogleDriveProvider?> connect({
  bool forceInteractive = false,
  List<String>? scopes,
  // NEW: Client ID and Secret are required for the desktop flow.
  String? serverClientId,
  String? clientSecret, // Secret is needed for the web app flow on desktop
  int redirectPort = 8000, // Default port used by the package
}) async {
  debugPrint("connect Google Drive,  forceInteractive: $forceInteractive");
  // Return existing instance if already connected and not forcing a new interactive session.
  if (_instance != null && _instance!.isAuthenticated && !forceInteractive) {
    return _instance;
  }
  if (scopes != null) {
    GoogleDriveProvider.scopes = scopes;
  }
  try {
    // 1. CONFIGURE: The new package uses a parameters object for configuration.
    final signInParams = all_platforms.GoogleSignInParams(
      clientId: serverClientId,
      clientSecret: clientSecret, // May be null for other client types
      scopes: GoogleDriveProvider.scopes,
      redirectPort: redirectPort,
    );

    // 2. INITIALIZE: Create the GoogleSignIn instance with the params.
    _googleSignIn ??= all_platforms.GoogleSignIn(params: signInParams);

    // 3. SIGN IN: The sign-in flow is simplified.
    // signIn() attempts offline (silent) first, then falls back to online.
    // signInOnline() forces the interactive flow.
    all_platforms.GoogleSignInCredentials? credentials;
    if (forceInteractive) {
      credentials = await _googleSignIn!.signInOnline();
    } else {
      credentials = await _googleSignIn!.signIn();
    }

    if (credentials == null) {
      debugPrint('User cancelled Google Sign-In process.');
      return null;
    }

    // 4. GET CLIENT: The authenticatedClient getter is now used.
    // The separate requestScopes() call is no longer needed as scopes are
    // handled during the signIn process.
    final http.Client? client = await _googleSignIn!.authenticatedClient;

    if (client == null) {
      debugPrint('Failed to get authenticated Google client.');
      await signOut();
      return null;
    }

    // Wrap the client in a RetryClient to handle transient network errors (5xx).
    final retryClient = RetryClient(
      client,
      retries: 3,
      when: (response) => {500, 502, 503, 504}.contains(response.statusCode),
      onRetry: (request, response, retryCount) => debugPrint(
          'Retrying request to ${request.url} (Retry #$retryCount)'),
    );

    // Create or update the singleton instance with the authenticated client.
    final provider = _instance ?? GoogleDriveProviderDesktop.internal();
    provider.driveApi = drive.DriveApi(retryClient);
    provider.isAuthenticated = true;
    provider._accessToken = credentials.accessToken;
    _instance = provider;
    debugPrint('Google Drive user signed in successfully.');
    return _instance;
  } on SocketException catch (e) {
    debugPrint(
        'No internet connection during Google Drive sign-in: ${e.message}');
    throw NoConnectionException(e.message);
  } catch (error) {
    debugPrint(
      'Error occurred during the Google Drive connect process: $error',
    );
    if (error is PlatformException && error.code == 'network_error') {
      throw NoConnectionException(error.toString());
    }
    await signOut(); // Clean up on error.
    return null;
  }
}