The getter 'bodyBytes' isn't defined for the type 'Future<Response> Function(Uri, {Map<String, String>? headers})' - firebase

I have updated dat to version 2.12 and I am getting this error:
The getter 'bodyBytes' isn't defined for the type 'Future Function(Uri, {Map<String, String>? headers})'.
Try importing the library that defines 'bodyBytes', correcting the name to the name of an existing getter, or defining a getter or field named 'bodyBytes'.
By code is like the following below:
I am getting 2 red lines below as
"bodyBytes": 1
"result.paths.first": 2
Code
pdf.dart:
class PDFApi {
static Future<File> loadAsset(String path) async {
final data = await rootBundle.load(path);
final bytes = data.buffer.asUint8List();
return _storeFile(path, bytes);
}
static Future<File> loadNetwork(String url) async {
final response = await http.get; Uri.parse(url);
final bytes = response.bodyBytes; <-- here: "bodyBytes": 1
return _storeFile(url, bytes);
}
static Future<File?> pickFile() async {
final result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['pdf'],
);
if (result == null) return null;
return File(result.paths.first); <-- here: "result.paths.first": 2
}
static Future<File?> loadFirebase(String url) async {
try {
final refPDF = FirebaseStorage.instance.ref().child(url);
final bytes = await refPDF.getData();
return _storeFile(url, bytes!);
} catch (e) {
return null;
}
}
static Future<File> _storeFile(String url, List<int> bytes) async {
final filename = basename(url);
final dir = await getApplicationDocumentsDirectory();
final file = File('${dir.path}/$filename');
await file.writeAsBytes(bytes, flush: true);
return file;
}
}

I changed final response = await http.get; Uri.parse(url); to final response = await http.get(Uri.parse(url)); thnx to pskink and return File(result.paths.first); to return File(result.paths.first!); , then it works just fine.

Related

Check if document exists, if not create and add data Firebase

As above I need create a function that returns "true" if a document exists, otherwise "false".
If the document doesn't exists then It need to be created before the function ends.
When I run it I have this exception :
Unhandled Exception: 'package:cloud_firestore/src/firestore.dart': Failed assertion: line 129 pos 12:
'isValidDocumentPath(documentPath)': a document path must point to a valid document.
Is pretty easy to understand that I'm not checking if the path exists before getting the collection but I don't know how to handle it.
This is the code:
Future<bool> checkMissingId(String id) async {
String str = id.toLowerCase();
String letter = str[0];
final snapShot =
await FirebaseFirestore.instance.collection(letter).doc(str).get();
if (snapShot == null || !snapShot.exists) {
//if not exists then create it
final _service = FirestoreService.instance;
_service.setData(
path: letter + str,
data: {'id': id},
);
return true;
} else // it already exists, return false
return false;
}
EDIT : new code but still doesn't work :
Future<bool> checkMissingId(String id) async {
String str = id.toLowerCase();
String letter = str[0];
String path = letter + "/" + str;
print(path);
try {
final snapShot =
await FirebaseFirestore.instance.collection(path).doc(str).get();
if (snapShot == null || !snapShot.exists) {
return true;
} else
return false;
} catch (e) {
print(e);
return false;
}
}
Future<bool> setId(String id) async {
String str = id.toLowerCase();
String letter = str[0];
String path = letter + "/" + str;
final _service = FirestoreService.instance;
try {
final snapShot =
await FirebaseFirestore.instance.collection(path).doc(str).get();
if (snapShot == null || !snapShot.exists) {
_service.setData(
path: path,
data: {'id': id},
);
return true;
} else
return false;
} catch (e) {
//print(e);
_service.setData(
path: path,
data: {'id': id},
);
return true;
}
}
Assuming id = "PaninoAvvelenato" :
I want to check if exists the document on path "p/paninoavvelenato", if not I need to create it.
Instead of using FirestoreService.
Future<bool> setId(String id) async {
String str = id.toLowerCase();
String letter = str[0];
try {
final snapShot = await FirebaseFirestore.instance.collection(letter).doc(str).get();
if (snapShot.exists) {
return false;
} else {
await FirebaseFirestore.instance.collection(letter).doc(str).set({'id': id});
return true;
}
} catch (e) {
// TODO: Do something clever.
return true;
}
}
It looks like document for path str is not exist and FirebaseFirestore.instance.collection(letter).doc(str).get(); throw exception
so better to place this code inside :
try {
// code that might throw an exception
FirebaseFirestore.instance.collection(letter).doc(str).get();
}
on Exception1 {
// code for handling exception
}
catch Exception2 {
// code for handling exception
}

A value of type 'Future<String>' can't be assigned to a variable of type 'String'

I have this code where am supposed to upload an image and get the downloaded url but whenever i do that I get this error
my url is String url;. So please why is this not working as it is supposed to
PS
I checked other website to learn how to properly upload but it keeps giving me an error or is there a better way to do this.
My code image
uploadTask.whenComplete(()async{
url = await refs.getDownLoadURL();
....
});
Since it returns a Future you need to wait for it to be accessed
Example :
Future<String> createFolder(String folderName) async {
final dir = Directory(
'${(io.Platform.isAndroid ? await getExternalStorageDirectory() //FOR ANDROID
: await getApplicationSupportDirectory() //FOR IOS
)!.path}/$folderName');
var status = await Permission.storage.status;
if (!status.isGranted) {
await Permission.storage.request();
}
if ((await dir.exists())) {
return dir.path;
} else {
dir.create();
return dir.path;
}
}
Future<String> getIslamiSahittoBookFilePath(String savename) async {
Future<String> s = createFolder("Islami_Sahitto");
String filePath = await s;
Map<Permission, PermissionStatus> statuses = await [
Permission.storage,
//add more permission to request here.
].request();
io.File? f = null;
if (statuses[Permission.storage]!.isGranted) {
Directory? dir = await DownloadsPath.downloadsDirectory();
if (dir != null) {
String savePath = "${dir.path}/$filePath/$savename";
f = new io.File(savePath);
if (await f.exists()) {}
}
}
return f.toString();
}
Now this block You can use AnyWhere : Future String, to String :
bool isPreviousDownloaded = false;
String previousFilePath = "null";
getIslamiSahittoBookFilePath(fileNameToDownload).then((value) {
if (value != null) {
setState(() {
isPreviousDownloaded = true;
previousFilePath = value;
});
}
});

How to make Digest Authentication with http in Flutter?

I am trying to make an ApI request with Digest Authentication. I found an answer to the above question FLUTTER How to implement Digest Authentification but it is not very clear. The docs for digest are very minimal.
Following is my code
import 'package:http/io_client.dart' as io_client;
import 'package:http/http.dart' as http;
try {
HttpClient authenticatingClient = HttpClient();
authenticatingClient.authenticate = (uri, scheme, realm) {
authenticatingClient.addCredentials(
uri,
realm,
HttpClientDigestCredentials(
DIGEST_AUTH_USERNAME, DIGEST_AUTH_PASSWORD));
return Future.value(true);
};
http.Client client = io_client.IOClient(authenticatingClient);
final response = await client.post(LOGIN_URL, body: {
"username": userName,
"password": password,
"user_group": 2
}).timeout(const Duration(seconds: 20));
if (response.statusCode == 200) {
debugPrint(response.body);
CurvesLoginModel curvesLoginModel = standardSerializers.deserializeWith(
CurvesLoginModel.serializer, json.decode(response.body));
return curvesLoginModel;
} else {
return null;
}
} on TimeoutException catch (_) {
return null;
} on SocketException catch (_) {
return null;
}
}
But what is realm in addCredentials.
Also is this the way to implement Digest Authentication in http for Flutter?
As soon as I hit my endpoint I get the following error Unhandled Exception: type 'int' is not a subtype of type 'String' in type cast
Realm is an arbitrary string provided by the web server to help you decide which username to use, in case you have more than one. It's sort of analogous to domain. In one domain your username might be fbloggs, in another fredb. By telling you the realm/domain you know which to provide.
Your cast problem is caused by using the value 2 in the body. That must be a Map<String, String>, but you have provided an integer. Replace it with 2.toString().
If somebody wants to know how to make digest auth with http then it is as follows
import 'dart:async';
import 'dart:convert';
import 'dart:math' as math;
import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart' as crypto;
import 'package:http/http.dart' as http;
class DigestAuthClient extends http.BaseClient {
DigestAuthClient(String username, String password, {inner})
: _auth = DigestAuth(username, password),
// ignore: prefer_if_null_operators
_inner = inner == null ? http.Client() : inner;
final http.Client _inner;
final DigestAuth _auth;
void _setAuthString(http.BaseRequest request) {
request.headers['Authorization'] =
_auth.getAuthString(request.method, request.url);
}
#override
Future<http.StreamedResponse> send(http.BaseRequest request) async {
final response = await _inner.send(request);
if (response.statusCode == 401) {
final newRequest = copyRequest(request);
final String authInfo = response.headers['www-authenticate'];
_auth.initFromAuthorizationHeader(authInfo);
_setAuthString(newRequest);
return _inner.send(newRequest);
}
// we should reach this point only with errors other than 401
return response;
}
}
Map<String, String> splitAuthenticateHeader(String header) {
if (header == null || !header.startsWith('Digest ')) {
return null;
}
String token = header.substring(7); // remove 'Digest '
var ret = <String, String>{};
final components = token.split(',').map((token) => token.trim());
for (final component in components) {
final kv = component.split('=');
ret[kv[0]] = kv.getRange(1, kv.length).join('=').replaceAll('"', '');
}
return ret;
}
String md5Hash(String data) {
var content = const Utf8Encoder().convert(data);
var md5 = crypto.md5;
var digest = md5.convert(content).toString();
return digest;
}
// from http_retry
/// Returns a copy of [original].
http.Request _copyNormalRequest(http.Request original) {
var request = http.Request(original.method, original.url)
..followRedirects = original.followRedirects
..persistentConnection = original.persistentConnection
..body = original.body;
request.headers.addAll(original.headers);
request.maxRedirects = original.maxRedirects;
return request;
}
http.BaseRequest copyRequest(http.BaseRequest original) {
if (original is http.Request) {
return _copyNormalRequest(original);
} else {
throw UnimplementedError(
'cannot handle yet requests of type ${original.runtimeType}');
}
}
// Digest auth
String _formatNonceCount(int nc) {
return nc.toRadixString(16).padLeft(8, '0');
}
String _computeHA1(String realm, String algorithm, String username,
String password, String nonce, String cnonce) {
String ha1;
if (algorithm == null || algorithm == 'MD5') {
final token1 = "$username:$realm:$password";
ha1 = md5Hash(token1);
} else if (algorithm == 'MD5-sess') {
final token1 = "$username:$realm:$password";
final md51 = md5Hash(token1);
final token2 = "$md51:$nonce:$cnonce";
ha1 = md5Hash(token2);
}
return ha1;
}
Map<String, String> computeResponse(
String method,
String path,
String body,
String algorithm,
String qop,
String opaque,
String realm,
String cnonce,
String nonce,
int nc,
String username,
String password) {
var ret = <String, String>{};
// ignore: non_constant_identifier_names
String HA1 = _computeHA1(realm, algorithm, username, password, nonce, cnonce);
// ignore: non_constant_identifier_names
String HA2;
if (qop == 'auth-int') {
final bodyHash = md5Hash(body);
final token2 = "$method:$path:$bodyHash";
HA2 = md5Hash(token2);
} else {
// qop in [null, auth]
final token2 = "$method:$path";
HA2 = md5Hash(token2);
}
final nonceCount = _formatNonceCount(nc);
ret['username'] = username;
ret['realm'] = realm;
ret['nonce'] = nonce;
ret['uri'] = path;
ret['qop'] = qop;
ret['nc'] = nonceCount;
ret['cnonce'] = cnonce;
if (opaque != null) {
ret['opaque'] = opaque;
}
ret['algorithm'] = algorithm;
if (qop == null) {
final token3 = "$HA1:$nonce:$HA2";
ret['response'] = md5Hash(token3);
} else if (qop == 'auth' || qop == 'auth-int') {
final token3 = "$HA1:$nonce:$nonceCount:$cnonce:$qop:$HA2";
ret['response'] = md5Hash(token3);
}
return ret;
}
class DigestAuth {
DigestAuth(this.username, this.password);
String username;
String password;
// must get from first response
String _algorithm;
String _qop;
String _realm;
String _nonce;
String _opaque;
int _nc = 0; // request counter
String _cnonce; // client-generated; should change for each request
String _computeNonce() {
math.Random rnd = math.Random();
List<int> values = List<int>.generate(16, (i) => rnd.nextInt(256));
return hex.encode(values);
}
String getAuthString(String method, Uri url) {
_cnonce = _computeNonce();
_nc += 1;
// if url has query parameters, append query to path
var path = url.hasQuery ? "${url.path}?${url.query}" : url.path;
// after the first request we have the nonce, so we can provide credentials
var authValues = computeResponse(method, path, '', _algorithm, _qop,
_opaque, _realm, _cnonce, _nonce, _nc, username, password);
final authValuesString = authValues.entries
.where((e) => e.value != null)
.map((e) => [e.key, '="', e.value, '"'].join(''))
.toList()
.join(', ');
final authString = 'Digest $authValuesString';
return authString;
}
void initFromAuthorizationHeader(String authInfo) {
Map<String, String> values = splitAuthenticateHeader(authInfo);
_algorithm = values['algorithm'];
_qop = values['qop'];
_realm = values['realm'];
_nonce = values['nonce'];
_opaque = values['opaque'];
}
bool isReady() {
return _nonce != null;
}
}
Then when calling your api
final response =
await DigestAuthClient(DIGEST_AUTH_USERNAME, DIGEST_AUTH_PASSWORD)
.post(LOGIN_URL, body: {
"USERNAME": userName,
"PASSWORD": password,
"USER_GROUP": "2"
}).timeout(const Duration(seconds: 20));
All credit goes to the following library https://pub.dev/packages/http_auth

Flutter: Future.then() never getting invoked

I'm currently playing around with Futures in flutter. I've some async functions that return a Future object. I register a Listener on the Future object with then(), so that I can update the ui as soon as the value comes in.
But the result is empty, because then() returns before all notes are loaded from the file system.
Future<List<Note>> loadNotes() async {
NoteService().findAll().then((result) {
result.forEach((note) => print(note.title)); //not printing -> result is emtpty...
});
}
//NoteService class
Future<List<Note>> findAll() async {
return noteRepository.findAll();
}
//NoteRepository class
#override
Future<List<Note>> findAll() async {
final Directory dir = await directory;
dir.list().toList().then((List<FileSystemEntity> list) async {
List<String> paths = List();
list.forEach((entity) => paths.add(entity.path));
List<File> _files = List();
paths.forEach((path) => _files.add(File(path)));
List<Note> notes = await _extractNotes(_files);
return Future.value(notes);
});
return Future.value(List());
}
Future<List<Note>> _extractNotes(List<File> _files) async {
List<Note> notes = List();
_files.forEach((file) {
String content = file.readAsStringSync();
print('content: ' + content); //this is getting printed correctly to the console
Map<String, dynamic> a = jsonDecode(content);
if(a.containsKey('codeSnippets')) {
notes.add(SnippetNoteEntity.fromJson(jsonDecode(content)));
} else {
notes.add(MarkdownNoteEntity.fromJson(jsonDecode(content)));
}
});
return Future.value(notes);
}

Q:Flutter How to get value from parameter inside class

I'm newbie for android and flutter development, I want to ask something about push notification, I build firebase_messaging by own self because its not support big notification image
The problem is I cant get the _url
int _selectedTab = 1;
static String _url = "";
static const platform =
const MethodChannel('com.example.loop_app_flutter_v2');
#override
Future<void> _firebaseMessageListener() async {
String getRedirect;
String url;
try {
final String result =
await platform.invokeMethod('getFirebaseMessagePayload');
getRedirect = '$result';
Map<String, dynamic> notif = jsonDecode(getRedirect);
url = notif["url"]; //payload success and url show up
} on PlatformException catch (e) {
getRedirect = "Failed : '${e.message}'.";
}
this.loadNotificationData(getRedirect);
setState(() {
_url = url; // i want to assign url to _url and put in List Widget
print(url); //print show up url
});
}
#override
void initState() {
_firebaseMessageListener();
}
final List<Widget> _children = [
new MainArtikel(),
new Webpage(url: _url),
new FeedBack(),
new Setting()
];

Resources