Reputation: 1
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