Flutter - Open Location in Maps - android

Given lat and long.
Is there any fast/smart way to open maps google/apple in Flutter and head to directions ?
I'm using url_launcher for telephone calls, can i use the plugin to open link that open maps ?
_launchURL() async {
const url = 'https://www.google.com/maps/place/Al+qi,+ADoqi,+Giza+Governorate/#33.0523046,38.2009323,17z/data=!3m1!4b1!4m5!3m4!1s0x1458413a996ec217:0x2411f6b62d93ccc!8m2!3d30.05237!4d31.2031598';
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}

Yes you can do that using the url_launcher plugin. The following code will open Google Maps when the app is installed on the phone (otherwise it will open the browser):
void _launchMapsUrl(double lat, double lon) async {
final url = 'https://www.google.com/maps/search/?api=1&query=$lat,$lon';
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}

I created a plugin Map Launcher for that.
To find installed maps on a device you can use:
import 'package:map_launcher/map_launcher.dart';
final availableMaps = await MapLauncher.installedMaps;
And then launch by calling showMarker on it
await availableMaps.first.showMarker(
coords: Coords(31.233568, 121.505504),
title: "Shanghai Tower",
description: "Asia's tallest building",
);
Or just check if map available and launch it if so
if (await MapLauncher.isMapAvailable(MapType.google)) {
await MapLauncher.launchMap(
mapType: MapType.google,
coords: coords,
title: title,
description: description,
);
}

This solution will work on both Android and iOS platforms.
import 'dart:io' show Platform;
import 'package:flutter/foundation.dart';
import 'package:url_launcher/url_launcher.dart';
class MapsLauncher {
static String createQueryUrl(String query) {
var uri;
if (kIsWeb) {
uri = Uri.https(
'www.google.com', '/maps/search/', {'api': '1', 'query': query});
} else if (Platform.isAndroid) {
uri = Uri(scheme: 'geo', host: '0,0', queryParameters: {'q': query});
} else if (Platform.isIOS) {
uri = Uri.https('maps.apple.com', '/', {'q': query});
} else {
uri = Uri.https(
'www.google.com', '/maps/search/', {'api': '1', 'query': query});
}
return uri.toString();
}
static String createCoordinatesUrl(double latitude, double longitude,
[String? label]) {
var uri;
if (kIsWeb) {
uri = Uri.https('www.google.com', '/maps/search/',
{'api': '1', 'query': '$latitude,$longitude'});
} else if (Platform.isAndroid) {
var query = '$latitude,$longitude';
if (label != null) query += '($label)';
uri = Uri(scheme: 'geo', host: '0,0', queryParameters: {'q': query});
} else if (Platform.isIOS) {
var params = {'ll': '$latitude,$longitude'};
if (label != null) params['q'] = label;
uri = Uri.https('maps.apple.com', '/', params);
} else {
uri = Uri.https('www.google.com', '/maps/search/',
{'api': '1', 'query': '$latitude,$longitude'});
}
return uri.toString();
}
static Future<bool> launchQuery(String query) {
return launch(createQueryUrl(query));
}
static Future<bool> launchCoordinates(double latitude, double longitude,
[String? label]) {
return launch(createCoordinatesUrl(latitude, longitude, label));
}
}
Call it like this:
MapsLauncher.launchCoordinates(
37.4220041, -122.0862462, "address");

If you want to use address instead of lat, long, you can use the following.
Referencing https://developers.google.com/maps/documentation/urls/ios-urlscheme, daddr Sets the end point for directions searches
final url = 'comgooglemaps://?daddr=${Uri.encodeFull(address)}&directionsmode=driving';
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
and don't forget to add to Info.plist
<key>LSApplicationQueriesSchemes</key>
<array>
<string>comgooglemaps</string>
</array>

I used for this native method
try {
await platform.invokeMethod('showLocation', [event.location[0], event.location[1], event.title]);
} on Exception catch (ex) {
print('${ex.toString()}');
ex.toString();
}
And in android package
class MainActivity : FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
GeneratedPluginRegistrant.registerWith(this)
MethodChannel(flutterView, CHANNEL).setMethodCallHandler { call, result ->
if (call.method == "showLocation") {
val args = (call.arguments) as List<Any>
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("geo:${args[0]}, ${args[1]}?z=23&q=${args[0]},${args[1]}(${args[2]})")))
result.success(null)
} else {
result.notImplemented()
}
}
}
}

2022 solution
void _launchMapsUrl() async {
if (_locationData == null) return;
final url =
'https://www.google.com/maps/search/?api=1&query=${_locationData!.latitude},${_locationData!.longitude}';
Map<String, dynamic>? params = {
'api': '1',
'query': '${_locationData!.latitude},${_locationData!.longitude}'
};
final uri = Uri.https(
'www.google.com',
'/maps/search/',
params,
);
if (await canLaunchUrl(uri)) {
await launchUrl(uri);
} else {
_showErrorDialog(
errorText:
'Could not launch.\nCheck please if you have Google Maps Application on your device.');
throw 'Could not launch $url';
}
}

Related

The argument type 'Userr? Function(User?)' can't be assigned to the parameter type 'User Function(User?)'

import 'package:brew_crew/models/user.dart';
import 'package:firebase_auth/firebase_auth.dart';
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
Userr? _userFromFirebaseUser(User? user) {
return user != null ? Userr(uid: user.uid) : null;
}
Stream<User?> get user {
return _auth.authStateChanges().map(_userFromFirebaseUser);
}
Future signInAnon() async {
try {
UserCredential result = await _auth.signInAnonymously();
User? user = result.user;
return _userFromFirebaseUser(user!);
} catch (e) {
print(e);
return null;
}
}
}
you have written double rr in the function return type remove the one r
User? _userFromFirebaseUser(User? user) {
return user != null ? User(uid: user.uid) : null;
}

Http Headers in GraphQL Flutter

I am working with GraphQL. I need to pass parameters to Http headers. However, I see an option to pass only normal parameters (code below). PLEASE tell me how to do it!!
Query(
options: QueryOptions(
document: gql(userGraphQL),
variables: {
"..." : "..."
}
),
builder: ...
)
I have created this file to related the GraphQL
gql_utils.dart file
class GraphQLUtils {
static final GraphQLUtils _instance = GraphQLUtils._internal();
GraphQLClient? _client;
factory GraphQLUtils() {
return _instance;
}
GraphQLUtils._internal() {
final httpLink = HttpLink(
'your base url',
);
final authLink = AuthLink(
ignore: undefined_identifier
getToken: () async => 'Bearer $YOUR_PERSONAL_ACCESS_TOKEN',
);
var link = authLink.concat(httpLink);
var link = httpLink;
var link = httpLink;
final policies = Policies(
fetch: FetchPolicy.networkOnly,
);
_client = GraphQLClient(
cache: GraphQLCache(),
link: link,
defaultPolicies: DefaultPolicies(
watchQuery: policies,
query: policies,
mutate: policies,
),
);
}
Future<Map<String, dynamic>> queryRepo(
DocumentNode readRepositories, map) async {
final options = WatchQueryOptions(
document: readRepositories,
variables: map,
pollInterval: const Duration(seconds: 4),
fetchResults: true,
);
QueryResult result = await _client!.query(options);
if (result.hasException) {
Map<String, dynamic> response = <String, dynamic>{};
response['success'] = false;
response['message'] = result.exception!.graphqlErrors[0].message;
return response;
} else {
Map<String, dynamic> response = <String, dynamic>{};
response['success'] = true;
response['data'] = result.data;
return response;
}
}
}
this is Example query class
class UserQueries {
static final userInsertQuery = gql(r'''
mutation Insert_users($objects: [users_insert_input!]!, $onConflict: users_on_conflict) {
insert_users(objects: $objects, on_conflict: $onConflict) {
returning {
id
name
timestamp
}
}
}
''');
}
and how to call api
Future insertUserApi(String name) async {
try {
Map<String, dynamic> variables = <String, dynamic>{};
variables = {
"objects": [
{"name": name}
],
"onConflict": {
"constraint": "users_pkey",
"update_columns": [
"id",
"name",
]
}
};
await GraphQLUtils()
.queryRepo(UserQueries.userInsertQuery, variables)
.then((response) async {
if (response["data"] != null) {
print("----Data---:${response["data"]}");
Get.back();
} else {
Get.snackbar(
"Error",
"Something Went wrong",
);
}
});
} catch (e, st) {
Get.snackbar(
"Error",
e.toString(),
);
}
}

The following _TypeError was thrown building contro(dirty, state: _controState#9420e): type 'Null' is not a subtype of type 'String'

i have been trying to solve this error , after i login i was getting type 'Null' is not a subtype of type 'String' for about 5 seconds and after that the app successfully login, i do not know why this happen, i already add null check to the User but i still get the error . Below is my code, tell me if you need more info, Thanks for helping
class _controState extends State<contro> {
_controState();
User? user = FirebaseAuth.instance.currentUser;
UserModel loggedInUser = UserModel();
var role;
var email;
var id;
#override
void initState() {
super.initState();
FirebaseFirestore.instance
.collection("users") //.where('uid', isEqualTo: user!.uid)
.doc(user!.uid)
.get()
.then((value) {
this.loggedInUser = UserModel.fromMap(value.data());
}).whenComplete(() {
CircularProgressIndicator();
setState(() {
email = loggedInUser.email.toString();
role = loggedInUser.role.toString();
id = loggedInUser.uid.toString();
});
});
}
routing() {
if (role == 'Freelancer') {
return JobScreen(
id: id,
);
} else {
return JobScreenClient(
id: id,
);
}
}
#override
Widget build(BuildContext context) {
CircularProgressIndicator();
return routing();
}
}
inside your routing, role might be null before FirebaseFirestore's result get ready, try this:
routing() {
if(role == null){
return Container(); // show empty widget like this or what widget you want
}else if (role == 'Freelancer') {
return JobScreen(
id: id,
);
} else {
return JobScreenClient(
id: id,
);
}
}
You have to add async/await to your code, because it's future functions..
void initState() async {
super.initState();
await FirebaseFirestore.instance
.collection("users") //.where('uid', isEqualTo: user!.uid)
.doc(user!.uid)
.get()
.then((value) {
this.loggedInUser = UserModel.fromMap(value.data());
}).whenComplete(() {
CircularProgressIndicator();
setState(() {
email = loggedInUser.email.toString();
role = loggedInUser.role.toString();
id = loggedInUser.uid.toString();
});
});
}
routing() {
if(role == null){
return const Center(child: CircularProgressIndicator());
}else if (role == 'Freelancer') {
return JobScreen(
id: id,
);
} else {
return JobScreenClient(
id: id,
);
}
}

image_downloader: ^0.31.0 doesn't show error while download but it doesnt download

So, i'm trying to download a image with the url, i've tried the image_downloader package example code and it didn't show any error. The issue that i'm having is that the image isn't downloading but on the debug console doesn't say anything.
Future<void> _downloadImage(
String url, {
AndroidDestinationType? destination,
bool whenError = false,
String? outputMimeType,
}) async {
String? fileName;
String? path;
int? size;
String? mimeType;
try {
String? imageId;
if (whenError) {
imageId = await ImageDownloader.downloadImage(url,
outputMimeType: outputMimeType)
.catchError((error) {
if (error is PlatformException) {
String? path = "";
if (error.code == "404") {
print("Not Found Error.");
} else if (error.code == "unsupported_file") {
print("UnSupported FIle Error.");
path = error.details["unsupported_file_path"];
}
setState(() {
_message = error.toString();
_path = path ?? '';
});
}
print(error);
}).timeout(Duration(seconds: 10), onTimeout: () {
print("timeout");
return;
});
} else {
if (destination == null) {
imageId = await ImageDownloader.downloadImage(
url,
outputMimeType: outputMimeType,
);
} else {
imageId = await ImageDownloader.downloadImage(
url,
destination: destination,
outputMimeType: outputMimeType,
);
}
}
if (imageId == null) {
return;
}
fileName = await ImageDownloader.findName(imageId);
path = await ImageDownloader.findPath(imageId);
size = await ImageDownloader.findByteSize(imageId);
mimeType = await ImageDownloader.findMimeType(imageId);
} on PlatformException catch (error) {
setState(() {
_message = error.message ?? '';
});
return;
}
if (!mounted) return;
setState(
() {
var location = Platform.isAndroid ? "Directory" : "Photo Library";
_message = 'Saved as "$fileName" in $location.\n';
_size = 'size: $size';
_mimeType = 'mimeType: $mimeType';
_path = path ?? '';
if (!_mimeType.contains("video")) {
_imageFile = File(path!);
}
return;
},
);
}
and i'm calling it like this
and it shows this in the console
this is the package
https://pub.dev/packages/image_downloader/example
Images doesn't show in gallery
Check above link , it may helpful to you.
You may find Image_gallery_saver too for downloading your image , And if still you go with existing package then you raise a issue with it.

ArgumentError (Invalid argument(s): Invalid internet address newsapi.org)

i have got runtime error "invalid internet address" but the api works fine .
Exception has occurred.
HttpException (HttpException: , uri = https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=d2c9e9553c4647f3add970ed74a812ee)
class News {
List<ArticleModel> news = [];
Future<void> getNews() async {
String url;
url = "https://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=d2c9e9553c4647f3add970ed74a812ee";
var response = await http.get(Uri.parse(url));
var jsonData = jsonDecode(response.body);
if (jsonData['status'] == "ok") {
jsonData["articles"].forEach((element) {
if (element['urlToImage'] != null && element['description'] != null) {
ArticleModel articleModel = ArticleModel(
title: element['title'],
author: element['author'],
description: element['description'],
urlToImage: element['urlToImage'],
// publshedAt: DateTime.parse(element['publishedAt']),
content: element["content"],
url: element["url"],
);
news.add(articleModel);
}
});
}
}
}
The code worked for me after this change:
Future<void> getNews() async {
var url = Uri.parse('https://newsapi.org/v2/top-headlines?country=eg&apiKey=api');
var response = await http.get(url);

Categories

Resources