How to get a String from an AsyncSnapshot<String> in Flutter FutureBuilder? - async-await

I have an image I would like to load from a NetworkImage(url). I'm populating a Future<String> images; variable from an initial function and now I'm having trouble getting my FutureBuilder to read it as a String. I'm getting the error on the url as "The argument type AsyncSnapshot can not be assigned to the parameter type String" Here is my code...
Future<String> images;
Future<Null> getData() async {
FirebaseUser user = await FirebaseAuth.instance.currentUser;
user = await FirebaseAuth.instance.currentUser;
var userid = user.uid;
await fb.child('users/${userid}').onValue.listen((Event event) {
if (event.snapshot.value != null) {
name = event.snapshot.value['displayName'];
images = event.snapshot.value['image'];
} else {
name = "MyFavKPop";
}
});
}
new FutureBuilder<String>(
future: images, // a Future<String> or null
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return new Text('Press button to start');
case ConnectionState.waiting: return new Text('Awaiting result...');
default:
if (snapshot.hasError)
return new Text('Error: ${snapshot.error}');
else
return new CircleAvatar(
backgroundImage: new NetworkImage(snapshot.data.toString()) // getting NetworkImageError ..looking for String not Future<String>,
radius: 75.0,
);
}
}),

The resulting data is the AsyncSnapshot.data, not the instance of the snapshot itself. In your example, the cases should be:
switch (snapshot.connectionState) {
case ConnectionState.none:
return new Text('Press button to start');
case ConnectionState.waiting:
return new Text('Awaiting result...');
default:
if (snapshot.hasError)
return new Text('Error: ${snapshot.error}');
else {
return new CircleAvatar(
backgroundImage: new NetworkImage(snapshot.data),
radius: 75.0,
);
}
}
EDIT: The second issue is that you are not creating images correctly - you are assigning a String to a Future. Instead try using a completer to create a Future when your getData method finishes running.
Completer<String> _imageCompleter = new Completer<String>();
Future<String> get images => _imageCompleter.future;
Future<Null> getData() async {
...
_imageCompleter.complete(event.snapshot.value['image']);
}

Related

how to upload images in server using flutter and laravel api?

How to upload images in server using flutter with Laravel API? I tried using getx, its returning null. also I have image_picker and image_cropper package in my pubspec.yaml
Select Image from Gallery using File Picker
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:file_picker/file_picker.dart';
class ImageScreen extends StatefulWidget {
ImageScreen();
#override
State<ImageScreen> createState() => _ImageScreenState();
}
class _ImageScreenState extends State<ImageScreen> {
File file;
Future<File> uploadImage() async {
FilePickerResult result = await FilePicker.platform.pickFiles();
if (result != null) {
setState(() {
file = File(result.files.single.path);
});
print(result.files.single.path);
} else {
// User canceled the picker
}
return file;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onTap: () {
uploadImage();
},
child: Container(
color: Colors.green,
padding: EdgeInsets.all(5),
child: Text('Upload Image', style: TextStyle(fontSize: 16, color: Colors.white),)
),
),
);
}
}
Uploading Image to the server using http.multipartFile
static Future<dynamic> uploadImage({File file}) async {
try {
http.MultipartRequest request = new http.MultipartRequest("POST", _uri);
http.MultipartFile multipartFile = await http.MultipartFile.fromPath('file_name', file.path);
request.files.add(multipartFile);
var streamedResponse = await request.send();
var response = await http.Response.fromStream(streamedResponse);
if (response.statusCode == 200 ) {
return jsonDecode(response.body);
}
}
catch (e) {
return null;
}
}
final images = <File>[].obs;
Use this method for picking up images
Future pickImage(ImageSource source) async {
ImagePicker imagePicker = ImagePicker();
XFile pickedFile = await imagePicker.pickImage(source: source, imageQuality: 80);
File imageFile = File(pickedFile.path);
print(imageFile);
if (imageFile != null) {
images.add(imageFile);
} else {
Get.showSnackbar(GetSnackBar(message: "Please select an image file"));
}
}
Use this for uploading images to the server with your specific url.As I have used dio for uploading.You can use http as well.
Future<String> uploadImage(File file) async {
String fileName = file.path.split('/').last;
// you can edit it for your own convenience
var _queryParameters = {
'api_token': 'your token if required',
};
Uri _uri = 'Your base url'
var formData = FormData.fromMap({
"file": await MultipartFile.fromFile(file.path, filename: fileName),
});
var response = await dio.post(_uri, data: formData);
print(response.data);
if (response.data['data'] != false) {
return response.data['data'];
} else {
throw new Exception(response.data['message']);
}
}
This works for me, so maybe others might need it as well.
uploadImage(imageFile) async {
var stream = new http.ByteStream(
DelegatingStream.typed(imageFile.openRead()));
var length = await imageFile.length();
var uri = Uri.parse(
'http://192.168.5.196/ApiFileUploadTest/public/api/uploading-file-api');
var request = new http.MultipartRequest('POST', uri);
var multipartFile = new http.MultipartFile('file', stream, length,
filename: basename(imageFile.path));
request.files.add(multipartFile);
var response = await request.send();
print(response.statusCode);
response.stream.transform(utf8.decoder).listen((value) {
print(value);
});
}

Cast Future<File> to base64 image with Flutter

Hi the flutter code below loads a photo from the camera roll and then displays it, on video, what I have to do is recover the path of the file, to do it I use the code below inside the inserimento function but when I run the code I the following error:
Try correcting the name to the name of an existing getter, or defining
a getter or field named 'path'. print("\n Immagine:
"+imageFile.path);
Flutter Code:
Future<File> imageFile;
//Costruttore
ArticoloEditPage(){
aggiornaValori();
BackButtonInterceptor.add(myInterceptor);
setData(new DateTime.now());
}
//Disabilito il bottone di back su android
bool myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) {
return true;
}
//Funzione di init
void init() {
aggiornaValori();
BackButtonInterceptor.add(myInterceptor);
}
//Funzione che esegue la creazione dell'utente
Future<bool> inserimento(BuildContext context) async {
print("\n Immagine: "+imageFile.path);
// var base64File=await Supporto.castDocumentToBase64(imgPath);
//print("\n Immagine in base64: "+imgPath);
}
pickImageFromGallery(ImageSource source) {
setState(() {
imageFile = ImagePicker.pickImage(source: source);
});
}
Widget showImage() {
return FutureBuilder<File>(
future: imageFile,
builder: (BuildContext context, AsyncSnapshot<File> snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
snapshot.data != null) {
return Image.file(
snapshot.data,
width: 300,
height: 300,
);
} else if (snapshot.error != null) {
return const Text(
'Errore caricamento non riuscito',
textAlign: TextAlign.center,
);
} else {
return const Text(
'Nessuna immagine selezionata',
textAlign: TextAlign.center,
);
}
},
);
}
you can not get path directly in future method,
so
by
1. this you can print your path.
Future<bool> inserimento(BuildContext context) async {
var pathData=await imageFile;
print("\n Immagine: "+pathData.path);
}
or
2. if you need path in widget
Widget showImage() {
return FutureBuilder<File>(
future: imageFile,
builder: (BuildContext context, AsyncSnapshot<File> snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
snapshot.data != null) {
print("Your Path : "+snapshot.data.path);
return Image.file(
snapshot.data,
width: 300,
height: 300,
);
} else if (snapshot.error != null) {
return const Text(
'Errore caricamento non riuscito',
textAlign: TextAlign.center,
);
} else {
return const Text(
'Nessuna immagine selezionata',
textAlign: TextAlign.center,
);
}
},
);
}
also
3. if you need base64 image.
then
Future<bool> inserimento(BuildContext context) async {
var pathData=await imageFile;
var base64Image = base64Encode(pathData.readAsBytesSync());
print("\n Immagine base64Image: "+base64Image.toString());
}

Image Picker not opening after asking permission on Android in flutter. [Wokring fine on IOS]

I am using a Cupertino switch for picking image from gallery. First time when user clicks it ask for permission. After getting the permission the imagePicker never opens the gallery. when i click the button again it shows
Image picker already active. If i close the app and open again it works fine. I have tried:
1. Flutter clean , flutter run
2. Upgrading the dependencies
Nothing works.
here is my code:
Widget _rightSectionPhoto() {
return new Container(
child: CupertinoSwitch(
value: isSwitchedforidPic,
onChanged: isSwitchedforidPicStatus
? (value) {
if (value == true) {
setState(() {
isSwitchedforidStatus = false;
getImage();
});
} else {
setState(() {
isImageUploaded = false;
});
}
}
: null,
activeColor: Colors.deepOrangeAccent,
),
);
}
And here is getImage function
Future getImage() async {
var image = await ImagePicker.pickImage(
source: ImageSource.gallery,
imageQuality: 10,
);
if (image == null) {
setState(() {
isSwitchedforidPic = false;
isSwitchedforidStatus = true;
isImageUploaded = false;
});
} else {
List<int> imageBytes = await image.readAsBytes();
base64Image = base64Encode(imageBytes);
setState(() {
isImageUploaded = true;
});
}
}

How to retreive image data in sqlite database in flutter?

I want to retrieve image data in sqlite. im using below code
var image = await ImagePicker.pickImage(source: imageSource);
List<int> bytes = await image.readAsBytes();
i want to take image and after save it sqlite.if can get and set image from sqlite database ?.
I found the solution in my question.
I'm getting the image from an image_picker and Encode it to BASE64 string value like below
Uint8List _bytesImage;
File _image;
String base64Image;
Future getImage() async {
var image2 = await ImagePicker.pickImage(
source: ImageSource.gallery,
);
List<int> imageBytes = image2.readAsBytesSync();
print(imageBytes);
base64Image = base64Encode(imageBytes);
print('string is');
print(base64Image);
print("You selected gallery image : " + image2.path);
_bytesImage = Base64Decoder().convert(base64Image);
setState(() {
_image=image2;
});
}
after creating an SQLite database dbhelper.dart file to retrieve String values and database model file Image.dart for the get and set the String values.
image.dart
class Image{
int id;
String image;
Employee(this.id, this.image);
Employee.fromMap(Map map) {
id= map[id];
image = map[image];
}
}
dbhelper.dart
class DBHelper {
static Database _db;
Future<Database> get db async {
if (_db != null) return _db;
_db = await initDb();
return _db;
}
initDb() async {
io.Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, "test.db");
var theDb = await openDatabase(path, version: 1, onCreate: _onCreate);
return theDb;
}
void _onCreate(Database db, int version) async {
// When creating the db, create the table
await db.execute(
"CREATE TABLE Imagedata(id INTEGER PRIMARY KEY, image TEXT)");
print("Created tables");
}
void saveImage(Imagedata imagedata) async {
var dbClient = await db;
await dbClient.transaction((txn) async {
return await txn.rawInsert(
'INSERT INTO Imagedata(id, image) VALUES(' +
'\'' +
imagedata.id+
'\'' +
',' +
'\'' +
imagedata.image +
'\'' +
')');
});
}
Future<List<Imagedata>> getMyImage() async {
var dbClient = await db;
List<Map> list = await dbClient.rawQuery('SELECT * FROM Imagedata');
List<Imagedata> images= new List();
for (int i = 0; i < list.length; i++) {
images.add(new Imagedata(list[i]["id"], list[i]["image"]));
}
print(images.length);
return images;
}
Future<int> deleteMyImage(Imagedata imagedata) async {
var dbClient = await db;
int res =
await dbClient.rawDelete('DELETE * FROM Imagedata');
return res;
}
}
last getting String value from the database and Decode String value to the Image file.
Getting image from database
Future<List<Employee>> fetchImageFromDatabase() async {
var dbHelper = DBHelper();
Future<List<Imagedata>> images= dbHelper.getImages();
return images;
}
after Decode string value to the Image file
String DecoImage;
Uint8List _bytesImage;
FutureBuilder<List<Imagedata>>(
future: fetchImageFromDatabase(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return new
ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
DecoImage=snapshot.data[index].image;
_bytesImage = Base64Decoder().convert(DecoImage);
return new SingleChildScrollView(
child: Container(
child: _bytesImage == null
? new Text('No image value.')
: Image.memory(_bytesImage)
),
);
}
);
}
}
),
i think that is helpful for other flutter,sqlite developers
import 'dart:convert';
import 'dart:typed_data';
    Uint8List bytesImage1;
    bool bolWithImage1 = false;
    try {
      bytesImage1 =
          base64Decode(base64StringFromSql);
      bolWithImage1 = true;
    } catch (err) {}
i.e. if bolWithImage1 is true, the conversion is successful. You can then use image.memory(byteImage1, ......) to show the image in flutter.
You can also save the image as a BLOB (data type: UInt8List). Storing both as Blob (UInt8List) or String(with Base64encoder) in sqflite works. The key was to use MemoryImage instead of Image.memory. Otherwise you would get type 'Image' is not a subtype of type 'ImageProvider ' error.
//First create column in database to store as BLOB.
await db.execute('CREATE TABLE $photoTable($colId INTEGER PRIMARY KEY AUTOINCREMENT, $colmage BLOB)');
//User imagePicker to get the image
File imageFile = await ImagePicker.pickImage(source: ImageSource.camera, maxHeight: 200, maxWidth: 200, imageQuality: 70);
//Get the file in UInt8List format
Uint8List imageInBytes = imageFile.readAsBytesSync();
//write the bytes to the database as a blob
db.rawUpdate('UPDATE $photoTable SET $colImage = ?, WHERE $colId =?', [imageInBytes, colID]);
//retrieve from database as a Blob of UInt8List
var result = await db.query(photoTable, orderBy: '$colID ASC');
List<Photo> photoList = List<Photo>();
for (int i=0; i<result.length; i++){
photoList.add(Photo.fromMapObject(userMapList[i]));
}
//Map function inside Photo object
Photo.fromMapObject(Map<String, dynamic> map) {
this._id = map['id'];
this._imageFile = map['image'];
}
//Display the image using using MemoryImage (returns ImagePicker Object) instead of Image.memory (returns an Image object).
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircleAvatar(
backgroundImage: MemoryImage(Photo.image),
backgroundColor: Colors.blueGrey[50],
),
]);

Use progress bar dialog in async task using Future in Flutter

I want to create common class for execute API. Now i needed to add progress dialog while executing task and after complete task dialog should be dismiss.I google lot but not get appropriate solution So help me to achieve it.
For Http Client i used dio plugin.
Please help me for adding progress dialog in this class so when i create request using this class it added progress dialog while executing task. i create this type of class in java but now i want to add it in flutter.
HttpRequest.dart
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
class HttpRequest {
void post(BuildContext context,String url, dynamic data, HttpListener listener) {
Dio dio = new Dio();
dio.post(url, data: data)
.then((Response<dynamic> response) {
if (response.statusCode == 200) {
listener.onSuccess(response.data);
} else {
listener.onError("Error");
}
})
.catchError((Exception error) {
listener.onError(error.toString());
});
}
}
abstract class HttpListener {
void onSuccess(dynamic result);
void onError(String error);
}
It's better to show progressbar in widgets, not in common classes.
Use below example (using http package):
class HttpRequest {
final JsonDecoder _decoder = new JsonDecoder();
Future post(String url, dynamic data) async {
http.Response response = await http.post(url,body: data);
if(response.statusCode < 200 || response.statusCode > 300){
throw new Exception('Faild');
} else {
return _decoder.convert(response.body);
}
}
}
The button that calls post method:
child: MaterialButton(onPressed: () async {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}));
HttpRequest _util = new HttpRequest();
try{
var res = await _util.post('someurl',_data);
} catch(Exception) {
//Handle Exception
} finally {
Navigator.pop(context);
}
});
I made a public package, future_progress_dialog, which is the opposite concept of package.
You wanted to put progress dialog in the task. But I tried the opposite way, putting Future task into the dialog.
https://pub.dev/packages/future_progress_dialog
With this package you can make a progress dialog like this.
var result = await showDialog(
context: context,
child: FutureProgressDialog(future, 'Loading...'));
I hope this would be helpful.
It is better to do it in fully async mode
onPressed: () async {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return const Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
}));
authenticate().then((value) {
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: (context) => HomePage()));
}).onError((error, stackTrace) {
Navigator.pop(context);
_showErrorToast(context);
});
},

Resources