flutter dart error when installing google api calendar - dart

I will display a list of events from Google Calendar.
I followed the example already in the following link : How to use Google API in flutter?
and my script is as follows :
import 'package:http/http.dart' as http;
assumed I was logged in.
GoogleSignIn _googleSignIn = GoogleSignIn(
scopes: <String>[
'email',
'https://www.googleapis.com/auth/contacts.readonly',
'https://www.googleapis.com/auth/calendar'
],
);'
class GoogleHttpClient extends http.BaseClient {
Map<String, String> _headers;
GoogleHttpClient(this._headers) : super();
#override
Future<http.StreamedResponse> send(http.BaseRequest request) =>
super.send(request..headers.addAll(_headers)); //have error 'the method 'send' is always abstract in the supertype'
#override
Future<http.Response> head(Object url, {Map<String, String> headers}) =>
super.head(url, headers: headers..addAll(_headers));
}
void getCalendarEvents() async {
final authHeaders = _googleSignIn.currentUser.authHeaders;
final httpClient = new GoogleHttpClient(authHeaders); //have error "The argument type 'Future<Map<String, String>>' can't be assigned to the parameter type 'Map<String, String>'"
var calendar = new Calendar.CalendarApi(new http.Client());
var calEvents = calendar.events.list("primary");
calEvents.then((Calendar.Events events) {
events.items.forEach((Calendar.Event event) {print(event.summary);});
});
}
the above script cannot run because of an error.
the method 'send' is always abstract in the supertype
can someone help me?

If your code is based on How to use Google API in flutter? you'll see that I have a #override Future<StreamedResponse> send(...) in my code.
GoogleHttpClient extends abstract class IOClient that is missing an implementation of send, so the concrete subclass needs to implement it.
That's what the error message is about.

Replace StreamedResponse with IOStreamedResponse
add IOClient library
replace class GoogleHttpClient extends IOClient with class GoogleHttpClient extends http.BaseClient

1 This is error
//have error "The argument type 'Future<Map<String, String>>' can't be assigned to the parameter type 'Map<String, String>'"
fixed: add await ahead
Like below:
final authHeaders = await _googleSignIn.currentUser.authHeaders;
2: Change like below
var calendar = new Calendar.CalendarApi(new http.Client());
to
var calendar = new Calendar.CalendarApi(httpClient);
======> Final:
void getCalendarEvents() async {
final authHeaders = await _googleSignIn.currentUser.authHeaders;
final httpClient = new GoogleHttpClient(authHeaders);
var calendar = new Calendar.CalendarApi(httpClient);
var calEvents = calendar.events.list("primary");
calEvents.then((Calendar.Events events) {
events.items.forEach((Calendar.Event event) {print(event.summary);});
});
}
It worked for me.

Related

Error when using argument matcher in mocking methods in dart null safety

I am getting the following error message when using argument matcher, any, when mocking a method in dart tests using mockito in a null safe dart code base.
What steps need to be taken to fix this issue
error:
The argument type 'Null' can't be assigned to the parameter type 'int'.
Test code can be found here:
class MockNumberTriviaRepository extends Mock implements NumberTriviaRespository {}
void main() {
late GetConcreteNumberTrivia usecase;
late MockNumberTriviaRepository mockNumberTriviaRepository;
setUp(() {
mockNumberTriviaRepository = MockNumberTriviaRepository();
usecase = GetConcreteNumberTrivia(mockNumberTriviaRepository);
});
const tNumber = 1;
const tNumberTrivia = NumberTrivia(number: tNumber, text: "test");
test('should get trivia for the number from repository', () async {
//arrange
when(mockNumberTriviaRepository.getConcreteNumberTrivia(any)).thenAnswer((_) async => const Right(tNumberTrivia));
//act
final result = await usecase.execute(tNumber);
//assert
// UseCase should simply return whatever was returned from the Repository
expect(result, const Right(tNumberTrivia));
// Verify that the method has been called on the Repository
verify(mockNumberTriviaRepository.getConcreteNumberTrivia(tNumber));
verifyNoMoreInteractions(mockNumberTriviaRepository);
});
}
Implementation code can be found here:
abstract class NumberTriviaRespository {
Future<Either<Failure, NumberTrivia>> getConcreteNumberTrivia(int number);
Future<Either<Failure, NumberTrivia>> getRandomNumberTrivia();
}
abstract class Failure extends Equatable {
const Failure([List properties = const <dynamic>[]]);
}
class GetConcreteNumberTrivia {
final NumberTriviaRespository respository;
const GetConcreteNumberTrivia(this.respository);
Future<Either<Failure, NumberTrivia>> execute(int number) async {
return await respository.getConcreteNumberTrivia(number);
}
}
class NumberTrivia extends Equatable {
final String text;
final int number;
const NumberTrivia({required this.text, required this.number});
#override
List<Object?> get props => [text, number];
}
Mockito has issues with Dart Null-safety. Please see https://github.com/dart-lang/mockito/blob/master/NULL_SAFETY_README.md.
You can override the implementation of your mock class to support a null argument by following the recipes on the link above:
class MockNumberTriviaRepository extends Mock
implements NumberTriviaRespository {
#override
Future<Either<Failure, NumberTrivia>> getConcreteNumberTrivia(int? number) =>
super.noSuchMethod(Invocation.method(#getConcreteNumberTrivia, [number]),
returnValue: Future.value(
Right<Failure, NumberTrivia>(NumberTrivia(text: "", number: 1))));
}

Dart2 Router Implementation

I am trying to upgrade Dart1 application to Dart 2.4, I am facing a problem in Router my code is as shown below
import 'dart:async';
import 'dart:convert';
import 'package:angular/src/core/di/decorators.dart';
#Injectable()
class SpRouterImpl implements SpRouter {
final Router _router;
SpRouterImpl(this._router);
#override
void go(String routeName, Map<String, String> parameters,
[bool openInNewWindow = false]) {
if (openInNewWindow) {
var url = _router.generate([routeName, parameters]).component.urlPath;
window.open(url, "_blank");
} else {
_router.navigate([routeName, parameters]);
}
}
}
I am getting error in this line
var url = _router.generate([routeName, parameters]).component.urlPath;
The method generate isn't defined for the class Router
Second error is here
_router.navigate([routeName, parameters]);
The argument type List can't be assigned to the parameter type 'String'
The above function is working fine in Dart 1 but when I upgrade to Dart 2, I am getting the errors, don't know how to solve it.
Can anyone help in this regard
You need a RoutePath instance to define your "route".
final search = RoutePath(path: "search/:term"); // term is the parameter
Then use that path to navigate to that route.
_router.navigate(search.toUrl(parameters: {'term': searchTerm}));
So in your case it might look like this:
import 'dart:async';
import 'dart:convert';
import 'package:angular/src/core/di/decorators.dart';
#Injectable()
class SpRouterImpl implements SpRouter {
final Router _router;
SpRouterImpl(this._router);
#override
void go(String routeName, Map<String, String> parameters,
[bool openInNewWindow = false]) {
final path = RoutePath(routeName);
final url = path.toUrl(parameters: parameters)
if (openInNewWindow) {
window.open(url, "_blank");
} else {
_router.navigate(url);
}
}
}
It might not drop in and work depending on how your routeName is defined but this is the general idea.
There are several other options for RoutePath check them out and see what works best for you!

Flutter _TypeError (type 'List<dynamic>' is not a subtype of type 'Map<String, dynamic>')

I am new to flutter and getting type error. I am trying to use json automated serializations.
AFTER DOING SOME TWEAKS HERE IS HOW IT LOOKS LIKE
Here is how I am trying to get the data from api
Future getMyProduct() async {
final res = await http.get('url');
final data = json.decode(res.body);
BaseResponse req = new BaseResponse.fromJson(data);
return req;
}
My BaseResponse class looks like this
import 'package:dynamicapp/model/model.dart';
import 'package:json_annotation/json_annotation.dart';
part 'response.g.dart';
#JsonSerializable()
class BaseResponse extends Object {
final int id;
final int sellingPrice;
final int totalStock;
final String productName;
final String productDesc;
final List<Image> images;
BaseResponse(this.id, this.sellingPrice, this.totalStock, this.productName,
this.productDesc, this.images);
factory BaseResponse.fromJson(Map<String, dynamic> json) => _$BaseResponseFromJson(json);
Map<String, dynamic> toJson() => _$BaseResponseToJson(this);
}
#JsonSerializable()
class Image extends Object {
final int id;
final String image;
// final int product_id;
Image(this.id, this.image);
factory Image.fromJson(Map<String, dynamic> json) => _$ImageFromJson(json);
Map<String, dynamic> toJson() => _$ImageToJson(this);
}
Could anyone please help me with this. I am stuck here. Have been trying different methods but none working. Thank you.
It looks like data is a List<dynamic>, then data.map(someFunc).toList() will take each element of data pass it to someFunc and form it back into a list of the return type of someFunc (which you will presumably want to be BaseResponse). Which tells you that someFunc needs to be a function that takes dynamic and returns BaseResponse.
You'd want to write something like this:
final data = json.decode(res.body);
List<BaseResponse> responses =
data.map((j) => BaseResponse.fromJson(j)).toList();

Getting BuildContext in Flutter for localization

I try to localize a String in Flutter with the localization package. The problem is the location where my translation is needed. It is not related to the UI, rather it is somewhere deep in my model, where I don't have access to a BuildContext. Is there any other possibility to still make use of the translation function?
// I don't have a context variable here
MyLocalizations.of(context).trans("foo")
Yes there is. You don't need BuildContext to access strings. Here is my solution:
class Strings {
Strings._(Locale locale) : _localeName = locale.toString() {
current = this;
}
final String _localeName;
static Strings current;
static Future<Strings> load(Locale locale) async {
await initializeMessages(locale.toString());
final result = Strings._(locale);
return result;
}
static Strings of(BuildContext context) {
return Localizations.of<Strings>(context, Strings);
}
String get title {
return Intl.message(
'Hello World',
name: 'title',
desc: 'Title for the Demo application',
);
}
}
Future<Null> main() async {
final Locale myLocale = Locale(window.locale);
await Strings.load(myLocale);
runApp(MyApplication());
}
Now you can reference a string as follows:
final title = Strings.current.title;
I know this question is dated way back. But I came across this issue when implementing my application, and I dont see any "nice" way to handle it.
So here is my approach
class LanguageService {
static String defaultLanguage = 'en';
static Map<String, Map<String, String>> _localizedValues = {
'en': {
'title': 'Storefront',
'language': 'Language',
'googleLogin': 'Login with Google'
},
'vn': {
'title': 'Cửa hàng',
'language': 'Ngôn ngữ',
'googleLogin': 'Đăng Nhập với Google'
}
};
static set language(String lang) {
defaultLanguage = lang;
}
static String get title {
return _localizedValues[defaultLanguage]['title'];
}
static String get language {
return _localizedValues[defaultLanguage]['language'];
}
static String get googleLogin {
return _localizedValues[defaultLanguage]['googleLogin'];
}
}
Now you can reference a string as follows:
String title = LanguageService.title;
You can find the detailed tutorial here
AppLocalitzations needs the context.
You can create a class (e.g., Localization) to encapsulate AppLocalizations initialization and initialize it from the home widget using its context. After, can be used with a mixin:
import 'package:flutter/widgets.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class Localization {
static AppLocalizations _loc;
AppLocalizations get loc => Localization._loc;
static void init(BuildContext context) => _loc = AppLocalizations.of(context);
}
In the home widget:
...
#override
Widget build(BuildContext context) {
Localization.init(context);
return Scaffold(
...
Access to loc in some class (it isn't necessary to be a Widget) using mixins:
class XXXWidget extends StatelessWidget with Localization {
...
Text(loc.xxxx)
...
}
class _XXXXWidgetState extends State<XXXWidget> with Localization {
...
Text(loc.xxxx)
...
}
class XXXXController with Localization {
...
cardNumberValidator = RequiredValidator(errorText: loc.commons_Required);
...
}
Null safety version:
class Localization {
static AppLocalizations? _l;
AppLocalizations get loc => Localization._l!;
static void init(BuildContext context) => _l = AppLocalizations.of(context)!;
}
No, there is no other way because it is stored using an InheritedWidget, which is a part of the build tree and thus can only be accessed with a reference to it (the BuildContext).
You will need to pass your context to somewhere deep in your model.
I am not sure if i did it right (from performance point of view) and maybe someone can comment on this but i have rx BehaviorSubject in my AppLocalization and fire event once new locales are loaded. I am listening to it in my main.dart and doing setState on receiving an event.
I checked performance tab but did not noticed any big changes in it once comparing my method vs accessing translations through context (inherited widget).

Dependency injection resolution of async factory

Having some issues with injecting a database connection into a class via the di.dart package. Specifically, resolving an async dependency in the toFactory option.
Both attempts result in the
NoSuchMethodError: Class '_Future' has no instance method 'query'.
error and it's unclear the correct path forward. I would prefer to keep the conn property without being wrapped in a Future. I've attempted doing the unwrapping of the Future in the class constructor but async constructors are not allowed in Dart at this time.
import 'package:postgresql/pool.dart';
import 'package:postgresql/postgresql.dart';
import 'package:di/di.dart';
main() async {
var uri = "postgres://username:password#localhost:5432/database";
var pool = new Pool(uri, minConnections: 2, maxConnections: 5);
await pool.start();
Module module = new Module();
module.bind(TestQuery);
module.bind(TestController);
module.bind(Pool, toValue: pool);
module.bind(Connection, toFactory: (pool) => pool.connect(), inject: [Pool]);
var injector = new ModuleInjector([module]);
var html = await injector.get(TestController).index();
print(html);
}
class BaseQuery {
Connection conn;
BaseQuery(Connection this.conn);
}
class TestQuery extends BaseQuery {
TestQuery(Connection conn) : super(conn); // type '_Future' is not a subtype of type 'Connection' of 'conn' where
run() async {
var results = await conn.query("select 1").toList();
// Do some data manipulation
return results;
}
}
class TestController {
TestQuery testQuery;
TestController(TestQuery this.testQuery);
index() async {
var results = await testQuery.run();
var html = "<pre>" + results.toString() + "</pre>";
return html;
}
}
I can reproduce but when I change the line to
var conn = await injector.get(Connection);
var res = await conn.query("select 1").toList();
it working fine.
I think your code should work as well though.

Resources