user27281925
user27281925

Reputation: 1

Error in searching gmail subject through flutter app

I'm new to dart and Flutter. I'm trying to implement gmail sign-in and once sign-in is done the next page should take me to search email by subject or content through this app. In the code I'm using GoogleHttpClient and passing header and auth. I can run the app and it does take me to gmail sign-in pop-up. But then the search page doesn't work. the error in the debug console comes as: Sign-In Error01: TypeError: Instance of 'BrowserClient': type 'BrowserClient' is not a subtype of type 'Map<String, String>'

Not sure what I'm missing.

My dart code below:

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:googleapis/gmail/v1.dart' as gmail;
import 'package:googleapis_auth/auth_io.dart';
import 'package:http/http.dart' as http;
import 'package:http/io_client.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Gmail Search App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const GmailSearchPage(),
    );
  }
}

class GmailSearchPage extends StatefulWidget {
  const GmailSearchPage({super.key});

  @override
  // ignore: library_private_types_in_public_api
  _GmailSearchPageState createState() => _GmailSearchPageState();
}

class _GmailSearchPageState extends State<GmailSearchPage> {
  final GoogleSignIn _googleSignIn = GoogleSignIn(
    scopes: [
      gmail.GmailApi.gmailReadonlyScope,
    ],
  );

  GoogleSignInAccount? _currentUser;
  gmail.GmailApi? _gmailApi;
  List<gmail.Message> _messages = [];
  bool _isSignedIn = false;

  @override
  void initState() {
    super.initState();
    _googleSignIn.onCurrentUserChanged.listen((GoogleSignInAccount? account) {
      setState(() {
        _currentUser = account;
        _isSignedIn = _currentUser != null;
      });
      if (_currentUser != null) {
        _handleSignIn();
      }
    });
    _googleSignIn.signInSilently();
  }

  Future<void> _handleSignIn() async {
    try {
      final authHeaders = await _currentUser!.authHeaders;
      final authenticateClient = GoogleHttpClient(http.Client() as Map<String, String>, authHeaders);
      print('NEW01: $authHeaders');
      print('NEW02: $authenticateClient');
      setState(() {
        _gmailApi = gmail.GmailApi(authenticateClient);
      });
    } catch (error) {
      print("Sign-In Error01: $error");
    }
  }

  Future<void> _signOut() async {
    await _googleSignIn.signOut();
    setState(() {
      _isSignedIn = false;
      _messages = [];
    });
  }

  Future<void> _searchEmails(String query) async {
    if (_gmailApi == null) return;

    var response = await _gmailApi!.users.messages.list('me', q: query);

    if (response.messages != null) {
      List<gmail.Message> messages = [];
      for (var message in response.messages!) {
        var detailedMessage = await _gmailApi!.users.messages.get('me', message.id!);
        messages.add(detailedMessage);
      }

      setState(() {
        _messages = messages;
      });
    } else {
      setState(() {
        _messages = [];
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Gmail Search App'),
        actions: [
          _isSignedIn
              ? IconButton(
                  icon: const Icon(Icons.logout),
                  onPressed: _signOut,
                )
              : const SizedBox.shrink(),
        ],
      ),
      body: _isSignedIn
          ? Column(
              children: [
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: TextField(
                    decoration: const InputDecoration(
                      labelText: 'Search Gmail',
                      border: OutlineInputBorder(),
                    ),
                    onSubmitted: (query) {
                      _searchEmails(query);
                    },
                  ),
                ),
                Expanded(
                  child: _messages.isEmpty
                      ? const Center(child: Text('No emails found.'))
                      : ListView.builder(
                          itemCount: _messages.length,
                          itemBuilder: (context, index) {
                            var message = _messages[index];
                            var snippet = message.snippet ?? 'No snippet available';
                            return ListTile(
                              title: Text(snippet),
                            );
                          },
                        ),
                ),
              ],
            )
          : Center(
              child: ElevatedButton(
                child: const Text('Sign in with Google'),
                onPressed: () async {
                  try {
                    await _googleSignIn.signIn();
                    print('NEW1: $_googleSignIn.signIn()');
                  } catch (error) {
                    print("Sign-In Error1: $error");
                  }
                },
              ),
            ),
    );
  }
}

class GoogleHttpClient extends IOClient {
  final Map<String, String> _headers;
  GoogleHttpClient(this._headers, Map<String, String> authHeaders) : super();
  @override
  Future<IOStreamedResponse> send(http.BaseRequest request) =>
  super.send(request..headers.addAll(_headers));
  @override
  Future<http.Response> head(url, {Map<String, String>? headers}) {
    return super.head(url, headers: headers?..addAll(_headers));
    }
}

I want to log in with gmail and then be able to search gmail's subject or content through the app. I want to pass the search text in the search box and hit the search button on the app.

Upvotes: 0

Views: 39

Answers (0)

Related Questions