In Flutter How to get image path after selecting images using Multi Image Picker? - api

I want to get an image path from selected multiple images, I'm using this link to select multiple images but I got assets, I want paths from selected multiple images because I want to upload into the API.
I added this dependency in pubspec.yaml If there any good way to do this, please tell me
multi_image_picker: ^4.6.3
This is my file upload class, This UI looks similar to Facebook.
import 'dart:typed_data';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:multi_image_picker/multi_image_picker.dart';
class UpdateStatus extends StatefulWidget {
#override
_UpdateStatusState createState() => _UpdateStatusState();
}
class _UpdateStatusState extends State<UpdateStatus> {
List<Asset> images = List<Asset>();
String _error = 'No Error Dectected';
Future<ByteData> byteData;
// List<int> imageData = byteData.buffer.asUint8List();
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Create Post'),
actions: <Widget>[
Padding(
padding: const EdgeInsets.all(18.0),
child: InkWell(child: Text('POST',style: TextStyle(fontSize: 18.0),),onTap: ()
{
print('Post this post');
},),
)
],
),
body: SingleChildScrollView(
child: Container(
height: MediaQuery.of(context).size.height,
width:MediaQuery.of(context).size.width ,
color: Colors.white,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
height: 300.0,
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
keyboardType: TextInputType.multiline,
maxLines: 100,
style: new TextStyle(
fontSize: 18.0,
color: Colors.black
),
decoration: InputDecoration(
hintText: 'Enter your Post Details Here !',
border: InputBorder.none,
),
),
),
),
Divider(
thickness: 1.0,
),
Column(
children: <Widget>[
Container(
height: 40.0,
color: Colors.white70,
child: Padding(
padding:EdgeInsets.only(left: 18.0,),
child: InkWell(
child: Row(
children: <Widget>[
Icon(Icons.add_a_photo,),
Text(" Choose Image",style: TextStyle(fontSize: 24.0,),),
],
),
onTap: ()
{
print(images.toList().toString());
print('choose image from local');
},
),
),
),
Divider(
thickness: 1.0,
),
Container(
height: 40.0,
color: Colors.white70,
child: Padding(
padding:EdgeInsets.only(left: 18.0,),
child: InkWell(
child: Row(
children: <Widget>[
Icon(Icons.add_photo_alternate,),
Text(" Choose Video",style: TextStyle(fontSize: 24.0,),),
],
),
onTap: ()
{
print('choose video from local');
},
),
),
),
],
),
Divider(
thickness: 1.0,
),
Container(
height: 200,
child: Column(
children: <Widget>[
Center(child: Text('Error: $_error')),
RaisedButton(
child: Text("Pick images"),
onPressed: loadAssets,
),
Expanded(
child: buildGridView(),
)
],
),
),
/*
Column(
children: <Widget>[
Center(child: Text('Error: $_error')),
RaisedButton(
child: Text("Pick images"),
onPressed: loadAssets,
),
Expanded(
child: buildGridView(),
)
],
),
*/
],
),
),
),
);
}
Future<void> loadAssets() async {
List<Asset> resultList = List<Asset>();
String error = 'No Error Dectected';
ByteData byteData;
try {
resultList = await MultiImagePicker.pickImages(
maxImages: 300,
enableCamera: true,
selectedAssets: images,
cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"),
materialOptions: MaterialOptions(
actionBarColor: "#abcdef",
actionBarTitle: "Ilma",
allViewTitle: "All Photos",
useDetailsView: false,
selectCircleStrokeColor: "#000000",
),
);
} on Exception catch (e) {
error = e.toString();
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
images = resultList;
_error = error;
print('000000000000000000000');
print('000000000000000000000');
print(images);
print('000000000000000000000');
print('000000000000000000000');
});
}
Widget buildGridView() {
return GridView.count(
crossAxisCount: 3,
children: List.generate(images.length, (index) {
Asset asset = images[index];
byteData=asset.getByteData();
print('0000');
print(byteData);
print('0000');
return AssetThumb(
asset: asset,
width: 300,
height: 300,
);
}),
);
}
}

Padding(
padding: const EdgeInsets.all(18.0),
child: InkWell(
child: Text(
'POST',
style: TextStyle(fontSize: 18.0),
),
onTap: () async {
List<MultipartFile> multipart = List<MultipartFile>();
for (int i = 0; i < images.length; i++) {
var path = await FlutterAbsolutePath.getAbsolutePath(images[i].identifier);
}
},
),
)

I'm Using below Code to select multiple images by using file_picker: ^2.0.7 Library.
Long press to select multiple image. Once Image Selected you can use f arr to display the images.
List<File> f = List();
RaisedButton(
child: Text("Pick Image"),
onPressed: () async {
FilePickerResult result = await FilePicker.platform.pickFiles(
allowMultiple: true,
type: FileType.custom,
allowedExtensions: ['jpg', 'png', 'jpeg'],
);
if (result != null) {
f = result.paths.map((path) => File(path)).toList();
setState(() {});
print(f);
}
},
),
Sample API Call For image upload and normal data. Image uploaded column should be arr ( photo[] ).
List<MultipartFile> newList = new List<MultipartFile>();
Future<String> ImageUpload() async {
var request = http.MultipartRequest('POST', url);
request.headers["Authorization"] = pref.getString("token");
request.headers["Accept"] = "application/json";
//Image Data
for (int i = 0; i < f.length; i++) {
newList.add(await http.MultipartFile.fromPath('photo[]', f[i].path));
}
request.files.addAll(newList);
Map<String, dynamic> data = Map<String, String>();
//normal data
data["user_id"] = user_id;
data["project_id"] = pro_id;
request.fields.addAll(data);
var res = await request.send();
if (res.statusCode == 200) {
debugPrint("Status${res}");
}else {
debugPrint("status code${res}");
}
}
Try This You can select and upload multiple images easily. Thank you.

Use multi_image_picker 4.7.14 library to pick Multiple Images. use below code you can send selected asset image as a file. `
//Inside Widget Builder
FlatButton(
child: Image.asset(
"assets/images/camera.png",
color: Colors.grey,
),
onPressed: loadAssets,
),
SizedBox(
// height: SizeConfig.safeBlockHorizontal * 10,
height: MediaQuery.of(context).size.height / 2,
child: Column(
children: <Widget>[
Expanded(
child: buildGridView(),
),
],
),
)
List<File> fileImageArray = [];
List<String> f = List();
List<Asset> resultList = List<Asset>();
List<Asset> images = List<Asset>();
Future<void> loadAssets() async {
try {
resultList = await MultiImagePicker.pickImages(
maxImages: 4,
enableCamera: true,
selectedAssets: images,
cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"),
materialOptions: MaterialOptions(
actionBarColor: "#abcdef",
actionBarTitle: "Example App",
allViewTitle: "All Photos",
useDetailsView: false,
selectCircleStrokeColor: "#000000",
),
);
} on Exception catch (e) {
error = e.toString();
}
if (!mounted) return;
for (int i = 0; i < resultList.length; i++) {
var path =
await FlutterAbsolutePath.getAbsolutePath(resultList[i].identifier);
print(path);
f.add(File(path));
}
setState(() {
images = resultList;
});
// return fileImageArray;
}
//image PreView
Widget buildGridView() {
return GridView.count(
crossAxisCount: 4,
children: List.generate(images.length, (index) {
Asset asset = images[index];
return AssetThumb(
asset: asset,
width: 50,
height: 50,
);
}),
);
}
API Call : while image uploading place use multipart file
List<MultipartFile> newList = new List<MultipartFile>();
Future<String> multiImagePostAPI() async {
var request = http.MultipartRequest('POST', url);
request.headers["Authorization"] = pref.getString("token");
request.headers["Accept"] = "application/json";
for (int i = 0; i < f.length; i++) {
newList.add(await http.MultipartFile.fromPath('photo[]', f[i].path));
}
request.files.addAll(newList);
Map<String, dynamic> data = Map<String, String>();
data["user_id"] = user_id;
data["project_id"] = pro_id;
data["title"] = titleController.text;
request.fields.addAll(data);
var res = await request.send();
if (res.statusCode == 200) {
debugPrint("Status$res");
}else {
debugPrint("status : $res");
}
}

You can also select multiple images using file_picker: ^1.5.0+2 library and easy to get path of selected images
Future<int> getFilePath() async {
try {
files = await FilePicker.getMultiFile();
if (files == '') {
return 0;
}
else
{
setState(() {
this._filePath = files;
return 1;
});
}
} on PlatformException catch (e) {
print("Error while picking the file: " + e.toString());
}
}
show selected images by using ListView Builder like this
ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: _filePath.length,
itemBuilder: (context,c)
{
return Card(
child: Image.file(_filePath[c],
fit: BoxFit.fill,
width: 400,
height: 400,
),
);
}
),

Related

Flutter Multiple Checkbox From API

I have been able to display Json data from API in FutureBuilder Widget. However, the widget has checkbox for each list. Whenever I check on one list, the whole list get checked.
I want a help on how to check each list individually and be able to use the data of the selected list.
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:bottom_navy_bar/bottom_navy_bar.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:mar/Components/mydrawer.dart';
import 'package:mar/Services/auth.dart';
import 'package:mar/sccreens/readRequirements.dart';
import 'package:mar/sccreens/scanAnalysis.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../constants.dart';
import 'infoAnalysis.dart';
import 'login_screen.dart';
class Know extends StatefulWidget {
static String id = 'Know';
#override
_KnowState createState() => _KnowState();
}
class _KnowState extends State<Know> {
List sympotms = [];
int currentIndex = 2;
bool valuefirst = false;
int _bottomBarIndex = 0;
Auth _auth;
showdialogall(context, String mytitle, String mycontent) {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
title: Text(
mytitle,
style: TextStyle(color: Colors.deepOrange),
),
content: Text(mycontent),
actions: [
Center(
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
color: kMainColor,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ReadReq()),
);
},
child: Text(
"Requirements",
style: TextStyle(color: Colors.black),
)),
),
],
);
});
}
Future fetchdata() async {
var res = await http.get("http://10.0.2.2/medical/symptoms.php");
if (res.statusCode == 200) {
var obj = json.decode(res.body);
return obj;
}
}
bool isSearching = false;
#override
void initState() {
fetchdata().then((data) {
setState(() {
sympotms = data;
});
});
super.initState();
}
void _filterSymptoms(value) {
setState(() {
filteredsympotms = sympotms
.where(
(sym) => sym['name'].toLowerCase().contains(value.toLowerCase()))
.toList();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: kMainColor,
title: Text(
"Know Your Analysis",
style: TextStyle(
fontFamily: 'Pacifico',
),
),
actions: <Widget>[
FlatButton(
child: CircleAvatar(
child: Image(
image: AssetImage('images/icons/medical.png'),
),
backgroundColor: Colors.black,
),
onPressed: () {
Navigator.pushNamed(context, Scan.id);
},
),
],
centerTitle: true,
),
drawer: MyDrawer(),
body: Column(
children: [
Expanded(
child: sympotms.length > 0
? ListView.builder(
itemBuilder: (_, index) {
return Container(
child: Row(
children: [
SizedBox(width: 10),
Checkbox(
value: this.valuefirst,
onChanged: (bool value) {
setState(() {
valuefirst = value;
});
},
checkColor: Colors.greenAccent,
activeColor: Colors.black,
),
Text(
"${sympotms[index]['SymptomsName']}",
style: TextStyle(fontSize: 17.0),
),
],
),
);
},
itemCount: sympotms.length,
)
: Container(child: Center(child: Text("Loading..."))),
),
RaisedButton(
child: Text(
" Submit ",
style: TextStyle(fontSize: 20),
),
onPressed: () {
showdialogall(context, "Result !", "CBC Test");
},
// onPressed: showdialogall(context, "Result !", "CBC Test"),
color: Colors.green,
textColor: Colors.white,
splashColor: Colors.grey,
padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
),
],
),
//Navigation
bottomNavigationBar: BottomNavyBar(
animationDuration: Duration(milliseconds: 800),
curve: Curves.easeInOut,
selectedIndex: currentIndex,
onItemSelected: (index) async {
if (index == 0) {
Navigator.pushNamed(context, Scan.id);
}
if (index == 1) {
Navigator.pushNamed(context, Information.id);
}
if (index == 2) {
Navigator.pushNamed(context, Know.id);
}
if (index == 3) {
SharedPreferences pref = await SharedPreferences.getInstance();
pref.clear();
await _auth.signOut();
Navigator.popAndPushNamed(context, LoginScreen.id);
}
setState(() {
currentIndex = index;
});
},
items: <BottomNavyBarItem>[
BottomNavyBarItem(
icon: Icon(
Icons.camera_alt,
),
title: Text('Scan'),
activeColor: Colors.black,
inactiveColor: Colors.black,
),
BottomNavyBarItem(
icon: Icon(
Icons.perm_device_information,
),
title: Text('Information'),
activeColor: Colors.black,
inactiveColor: Colors.black,
),
BottomNavyBarItem(
icon: Icon(
Icons.open_in_new_outlined,
),
title: Text('Know analysis'),
activeColor: Colors.black,
inactiveColor: Colors.black,
),
],
),
);
}
}
I want a help on how to check each list individually and be able to use the data of the selected list.
this image display my problem
You can do it by storing the selected index in an array.
Here is the idea.
final selectedIndexes = [];
/// In List View
ListView.builder(
itemBuilder: (_, index) {
return Container(
child: Row(
children: [
SizedBox(width: 10),
Checkbox(
value: selectedIndexes.contains(index),
onChanged: (bool value) {
if(selectedIndexes.contains(index) {
selectedIndexes.remove(index); // unselect
} else {
selectedIndexes.add(index); // select
}
setState(() {});
},
checkColor: Colors.greenAccent,
activeColor: Colors.black,
),
Text(
"${sympotms[index]['SymptomsName']}",
style: TextStyle(fontSize: 17.0),
),
],
),
);
},
itemCount: sympotms.length,
)
Since now you have stored the indexes, you can get whatever data you want for selected checkboxes.

flutter_staggered_grid_view infinite scroll from api feed

I am using the flutter_staggered_grid_view package (https://github.com/letsar/flutter_staggered_grid_view) to have a feed of images. I want to implement something where first of all I can fetch say 30 images on initial screen load then when I reach the end and the scroll listener fires fetch more from the api. How do I change the below to do this? Can anyone give me any direction on docs etc. I think fundamentally this package is using gridview underneath but I am new to flutter so I'm unsure.
I just want an infinite scroll feed of images from an api.
class HomeScreen extends StatefulWidget {
_HomeState createState() => _HomeState();
}
class _HomeState extends State<HomeScreen> {
final scrollController = ScrollController();
#override
void initState() {
super.initState();
scrollController.addListener(() {
if (scrollController.position.maxScrollExtent ==
scrollController.offset) {
// Get more
print('End of screen');
}
});
}
List<String> imageList = [
'https://cdn.pixabay.com/photo/2020/12/15/16/25/clock-5834193__340.jpg',
'https://cdn.pixabay.com/photo/2020/09/18/19/31/laptop-5582775_960_720.jpg',
'https://media.istockphoto.com/photos/woman-kayaking-in-fjord-in-norway-picture-id1059380230?b=1&k=6&m=1059380230&s=170667a&w=0&h=kA_A_XrhZJjw2bo5jIJ7089-VktFK0h0I4OWDqaac0c=',
'https://cdn.pixabay.com/photo/2019/11/05/00/53/cellular-4602489_960_720.jpg',
'https://cdn.pixabay.com/photo/2017/02/12/10/29/christmas-2059698_960_720.jpg',
'https://cdn.pixabay.com/photo/2020/01/29/17/09/snowboard-4803050_960_720.jpg',
'https://cdn.pixabay.com/photo/2020/02/06/20/01/university-library-4825366_960_720.jpg',
'https://cdn.pixabay.com/photo/2020/11/22/17/28/cat-5767334_960_720.jpg',
'https://cdn.pixabay.com/photo/2020/12/13/16/22/snow-5828736_960_720.jpg',
'https://cdn.pixabay.com/photo/2020/12/15/16/25/clock-5834193__340.jpg',
'https://cdn.pixabay.com/photo/2020/09/18/19/31/laptop-5582775_960_720.jpg',
];
#override
Widget build(BuildContext context) {
/// If you set your home screen as first screen make sure call [SizeConfig().init(context)]
SizeConfig().init(context);
return Scaffold(
body: Platform.isIOS
? Container(
margin: EdgeInsets.only(left: 12, right: 12, top: 5),
child: CustomScrollView(
controller: scrollController,
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics()),
slivers: <Widget>[
SliverAppBar(
floating: true,
title: SvgPicture.asset(
"assets/images/logo-dark.svg",
height: getProportionateScreenWidth(40),
),
actions: [
// Filter Button
FlatButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FilterScreen(),
),
),
child: Text(
"Filter",
style: Theme.of(context).textTheme.bodyText1,
),
),
],
),
CupertinoSliverRefreshControl(
onRefresh: () async {
await Future.delayed(Duration(seconds: 2));
},
),
SliverStaggeredGrid.countBuilder(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 12,
itemCount: imageList.length,
itemBuilder: (context, index) {
return Container(
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.all(
Radius.circular(15),
),
),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(15)),
child: FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
image: imageList[index],
fit: BoxFit.cover,
),
),
);
},
staggeredTileBuilder: (index) {
return StaggeredTile.count(1, index.isEven ? 1.2 : 1.8);
},
)
],
),
)
: RefreshIndicator(
color: kMainColor,
displacement: 120,
onRefresh: () async {
await Future.delayed(Duration(seconds: 2));
},
child: Container(
margin: EdgeInsets.only(left: 12, right: 12, top: 5),
child: CustomScrollView(
controller: scrollController,
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics(),
),
slivers: <Widget>[
SliverAppBar(
floating: true,
title: SvgPicture.asset(
"assets/images/logo-dark.svg",
height: getProportionateScreenWidth(40),
),
actions: [
// Filter Button
FlatButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FilterScreen(),
),
),
child: Text(
"Filter",
style: Theme.of(context).textTheme.bodyText1,
),
),
],
),
SliverStaggeredGrid.countBuilder(
crossAxisCount: 2,
crossAxisSpacing: 10,
mainAxisSpacing: 12,
itemCount: imageList.length,
itemBuilder: (context, index) {
return Container(
decoration: BoxDecoration(
color: Colors.transparent,
borderRadius: BorderRadius.all(
Radius.circular(15),
),
),
child: ClipRRect(
borderRadius: BorderRadius.all(
Radius.circular(15),
),
child: FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
image: imageList[index],
fit: BoxFit.cover,
),
),
);
},
staggeredTileBuilder: (index) {
return StaggeredTile.count(1, index.isEven ? 1.2 : 1.8);
},
)
],
),
),
),
);
}
}
You need to add the ScrollController for the scrolling detection at the bottom for the ListView and GridView. As you need the GridView i have created the ScrollController listner and added to the GridView's contollerfor the detection of the scroll. I have created the demo of it , please check it once. At first time it load the 10 items and when list comes to the bottom then it add more 10 items in it.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class HomeScreen extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return HomeState();
}
}
class HomeState extends State<HomeScreen> {
List dataList = new List<int>();
bool isLoading = false;
int pageCount = 1;
ScrollController _scrollController;
#override
void initState() {
super.initState();
////LOADING FIRST DATA
addItemIntoLisT(1);
_scrollController = new ScrollController(initialScrollOffset: 5.0)
..addListener(_scrollListener);
}
Widget build(BuildContext context) {
return MaterialApp(
title: 'Gridview',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.red,
accentColor: Color(0xFFFEF9EB),
),
home: Scaffold(
appBar: new AppBar(),
body: GridView.count(
controller: _scrollController,
scrollDirection: Axis.vertical,
crossAxisCount: 2,
mainAxisSpacing: 10.0,
physics: const AlwaysScrollableScrollPhysics(),
children: dataList.map((value) {
return Container(
alignment: Alignment.center,
height: MediaQuery.of(context).size.height * 0.2,
margin: EdgeInsets.only(left: 10.0, right: 10.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
),
child: Text("Item ${value}"),
);
}).toList(),
)));
}
//// ADDING THE SCROLL LISTINER
_scrollListener() {
if (_scrollController.offset >=
_scrollController.position.maxScrollExtent &&
!_scrollController.position.outOfRange) {
setState(() {
print("comes to bottom $isLoading");
isLoading = true;
if (isLoading) {
print("RUNNING LOAD MORE");
pageCount = pageCount + 1;
addItemIntoLisT(pageCount);
}
});
}
}
////ADDING DATA INTO ARRAYLIST
void addItemIntoLisT(var pageCount) {
for (int i = (pageCount * 10) - 10; i < pageCount * 10; i++) {
dataList.add(i);
isLoading = false;
}
}
#override
void dispose() {
_scrollController.dispose();
super.dispose();
}
}
https://i.stack.imgur.com/7hcDc.gif

Cant get data's length in itemCount

I want to get my API data's length to use in Listview.builder widget. I want to get my data from API which is 'mahalle'. And this data is a list of data. I want to get this data's length to build a list. But I got an error like this:
#4 ComponentElement.performRebuild
package:flutter/…/widgets/framework.dart:4546
...
════════════════════════════════════════════════════════════════════════════════
════════ Exception caught by widgets library ═══════════════════════════════════
Class 'Future<dynamic>' has no instance getter 'length'.
Receiver: Instance of 'Future<dynamic>'
Tried calling: length
The relevant error-causing widget was
MahalleList
And the reference of the error is :
#action
Future<void> fetcMahalle() async {
// var data =
// await httpClient.getData(globals.SELECT_URL).then((mahalle) => mahalle);
networkService.getMahalle();
}
And I'm getting my data with :
Future getMahalle() async {
BaseOptions options = new BaseOptions(
baseUrl: globals.PROD_URL,
connectTimeout: 5000,
receiveTimeout: 3000,
);
Dio dio = new Dio(options);
dio.options.headers["Authorization"] = "Bearer ${globals.USER_TOKEN}";
try {
var response =
await dio.get(globals.SELECT_URL); //'api/hizlirapor/selects'
List<MahalleModel> mahalleList = response.data['mahalle']
.map<MahalleModel>((mahalle) => MahalleModel.fromJson(mahalle))
.toList();
return mahalleList;
} on DioError catch (e) {
debugPrint("ERRORR!!!!!!!!!!!!! ${e.error.toString()}");
return null;
}
}
And finally here's the widget I'm trying to use my list data's length :
Container _buildBody(
BuildContext context, ObservableFuture<List<MahalleModel>> future) {
return Container(
color: backgroundColor,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
_buildSearchBar(context),
RefreshIndicator(
onRefresh: mahalleStore.fetcMahalle,
child: ListView.builder(
physics: const AlwaysScrollableScrollPhysics(),
itemCount: mahalleList.length,
itemBuilder: (context, index) {
final mahalle = mahalleList[index];
return Container(
height: 100,
child: Card(
color: Colors.white,
margin: EdgeInsets.all(15),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(10),
),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
color: mainColor,
width: 3,
height: 50,
),
SizedBox(
width: 15,
),
Icon(
AppIcon.mahalle_raporu,
color: mainColor,
),
SizedBox(
width: 15,
),
Text(
mahalle.mahalleAdi,
style: textStyle,
),
],
),
),
);
}),
),
],
),
);
}
Thanks for your all help !
FutureBuilder(
future:mahalleStore.fetchMahalle,
builder: (context, snapshot){
//whatever returns from this function, will be avaliable inside snapshot paremeter.
final mahalleList= snapshot.data;
switch (snapshot.connectionState) {
case ConnectionState.waiting:
{
return Center(child: CircularProgressIndicator(),);
}
case ConnectionState.done:
if (snapshot.hasData) {
// do what you want here
}
return Text("Error occured");
default:
//
}});
I deleted previous comment , check this one.
You should use FutureBuilder because getMahalle returns a Future.

how to navigate to other page from streambuilder in flutter?

i am trying to implement login functionality using bloc pattern in flutter. So I want to navigate to main page after authentication is successful. from loginBloc.dart I will get the status inside the streamBuilder in login.dart when the status is success I want to navigate to main.dart but I cant able to understand how to call the main.dart inside the streamBuilder in login.dart.
login.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_svg/svg.dart';
import 'package:hotelorders/bloc/LoginBloc.dart';
import 'package:hotelorders/screens/Home.dart';
class Login extends StatefulWidget
{
#override
State<StatefulWidget> createState() {
return LoginState();
}
}
class LoginState extends State<Login>
{
final LoginBloc _loginBloc = LoginBloc();
String _email,_password;
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
#override
void dispose()
{
_loginBloc.dispose();
super.dispose();
}
Widget _progressBar()
{
return StreamBuilder<bool>(
stream: _loginBloc.progressStream,
builder: (BuildContext context,AsyncSnapshot<bool> snapShot) {
bool visible;
if(snapShot.data == null)
{
visible = false;
}
else
{
visible = snapShot.data;
}
return Visibility(
maintainSize: true,
maintainAnimation: true,
maintainState: true,
visible: visible,
child: Container(
child: Center(
child: SizedBox(
width: 60,
height: 60,
child: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey,
offset: Offset(0.0, 1.0), //(x,y)
blurRadius: 1.0,
),
],
),
),
Center(
child: CircularProgressIndicator(),
)
],
),
)
)
),
);
}
);
}
Widget _emailTextField()
{
return TextFormField(
decoration: InputDecoration(
labelText: "Email id",
border: OutlineInputBorder(
borderRadius: new BorderRadius.circular(32.0),
)
),
keyboardType: TextInputType.emailAddress,
validator: (String value){
if(value.isEmpty || !RegExp(r"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?").hasMatch(value))
{
return "Enter a valid email id";
}
return null;
},
onSaved: (String value){
_email = value;
},
);
}
Widget _passwordTextField()
{
return TextFormField(
decoration: InputDecoration(labelText: "Password",
filled: true,
border: OutlineInputBorder(
borderRadius: new BorderRadius.circular(32.0),
),
fillColor: Colors.white
),
keyboardType: TextInputType.text,
obscureText: true,
validator: (String value){
if(value.isEmpty)
{
return "Enter a valid password";
}
else if(value.length < 8)
{
return "Password is too short";
}
else
{
return null;
}
},
);
}
void _login()
{
if(!_formKey.currentState.validate())
{
return;
}
_formKey.currentState.save();
Map<String,String> map = new Map();
map['email'] = _email;
map['password'] = _password;
_loginBloc.login(map);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
SingleChildScrollView(
child: Container(
child: Column(
children: <Widget>[
Container(
alignment: Alignment.center,
margin: EdgeInsets.fromLTRB(0, 48, 0, 0),
child: Text(
"Take Orders and",
style: TextStyle(color: Theme.of(context).primaryColorDark,fontSize: 20),
),
),
Container(
child: Text(
"Track the Best Selling Items",
style: TextStyle(color: Theme.of(context).primaryColor,fontSize: 16),
),
),
Container(
margin: EdgeInsets.fromLTRB(16, 0, 16, 0),
child: SvgPicture.asset('assets/images/undraw_booking.svg',width: 100.0,height: 280.0,),
),
Container(
margin: EdgeInsets.fromLTRB(16, 0, 0, 0),
child:Row(
children: <Widget>[
Text(
"Login To ",
style: TextStyle(color: Colors.black,fontSize: 20)
),
Text(
"Take orders",
style: TextStyle(color: Theme.of(context).primaryColorDark,fontSize: 20),
)
],
),
),
Container(
margin: EdgeInsets.fromLTRB(16, 8, 16, 0),
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.fromLTRB(0, 8, 0, 0),
child: _emailTextField(),
),
Container(
margin: EdgeInsets.fromLTRB(0, 8, 0, 0),
child: _passwordTextField(),
),
Container(
margin: EdgeInsets.fromLTRB(0, 8, 0, 0),
child: Align(
alignment: Alignment.centerLeft,
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32.0)
),
padding: EdgeInsets.fromLTRB(64, 12, 64, 12),
color: Theme.of(context).accentColor,
textColor: Colors.white,
child: Text(
"Login",
),
onPressed: (){
_login();
},
) ,
),
),
StreamBuilder<dynamic>(
stream:_loginBloc.loginStateStream,
builder: (BuildContext context, AsyncSnapshot<dynamic> snapShot){
if(snapShot.data == "success")
{
// WidgetsBinding.instance.addPostFrameCallback((_){
// Navigator.push(context, MaterialPageRoute(
// builder: (context)=> Home()
// ));
// });
}
else if(snapShot.data != null && snapShot.data != "success")
{
WidgetsBinding.instance.addPostFrameCallback((_) {
Scaffold.of(context).showSnackBar(SnackBar(
content: Text('${snapShot.data}',
style: TextStyle(color: Colors.black),),
backgroundColor: Color(0xFFe5e5e5),
));
// showDialog(context: context,builder: (BuildContext con){
// return AlertDialog(
// title: Text('${snapShot.data}'),
// );
// });
});
}
return Container();
},
)
],
),
),
)
],
),
)
),
_progressBar(),
],
),
);
}
}
LoginBloc.dart
import 'dart:async';
class LoginBloc
{
// here event comes in and state goes out
//stream conntroller for output
final _loginStateController = StreamController<String>();
//stream controller for input
final _loginEventController = StreamController<Map<String,String>>();
final _progressController = StreamController<bool>();
StreamSink<String> get loginStateSink => _loginStateController.sink;
Stream<String> get loginStateStream => _loginStateController.stream;
Sink<Map<String,String>> get loginEventSink => _loginEventController.sink;
Stream<bool> get progressStream => _progressController.stream;
StreamSink<bool> get progressSink => _progressController.sink;
LoginBloc()
{
progressSink.add(false);
_loginEventController.stream.listen(login);
}
login(Map<String,String> loginDetails)
{
progressSink.add(true);
Timer(Duration(seconds: 3), () {
progressSink.add(false);
loginStateSink.add("success");
});
// when we pass data in sink we get the output from stream
}
void dispose()
{
_loginEventController.close();
_loginStateController.close();
_progressController.close();
}
}
You are almost there. The following should work :
if(snapShot.data == "success")
{
Navigator.push(
context, MaterialPageRoute(builder: (context)=> Home()));
}
Note : WidgetsBinding.instance.addPostFrameCallback is used to get a callback when widget tree is loaded.

Upload chosen image to the API in Flutter using image picker plugin

I want to upload the image into the API. I tried this code but I got an error
File not found
If I send an image file using Postman, it is working successfully. Here I attached the Postman screenshot, for upload the image I gave the image path and in addition for my document, I want to attach the user id please tell me a solution? thank you
This is my code
class _UserProfileEditState extends State<UserProfileEdit> {
// String imagepath='';
File _profileImage;
String base64Image;
DatabaseHelper databaseHelper = new DatabaseHelper();
int parentid;
_handleimagefromgallary() async {
File imagefile = await ImagePicker.pickImage(source: ImageSource.gallery);
if(imagefile!=null) {
setState(() {
_profileImage = imagefile;
});
}
}
_displayprofilephoto()
{
if(_profileImage==null)
{
if(widget.parentsInfo.data.photo==null)
{
return AssetImage('assets/images/parentimg.png');
}
else
{
return CachedNetworkImageProvider(widget.parentsInfo.data.photo);
}
}
else
{
return FileImage(_profileImage);
}
}
#override
Widget build(BuildContext context) {
parentid=widget.parentsInfo.data.id;
return Scaffold(
appBar: AppBar(
title: Center(
child: Text('Edit Profile'),
),
),
body: SingleChildScrollView(
child: Container(
height: MediaQuery.of(context).size.height * 1.5,
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: Container(
height: 160.0,
width: 160.0, //MediaQuery.of(context).size.width,
child: new CircleAvatar(
radius: 50.0,
backgroundColor: Colors.green,
backgroundImage: _displayprofilephoto(),
),
),
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(''),
InkWell(
child: Icon(Icons.add_photo_alternate),
onTap:_handleimagefromgallary,
),
],
),
),
showpdatebutton(),
This is the method to upload:
Future _updateprofilepicture() async{
// _profileImage=await FlutterAbsolutePath.getAbsolutePath(images[i].identifier);
// var path = await FlutterAbsolutePath.getAbsolutePath(images[i].identifier);
// var path =await FlutterAbsolutePath.getAbsolutePath(_profileImage.absolute.path);
var path=await FlutterAbsolutePath.getAbsolutePath(_profileImage.path);
if(path==null)
{
}
else
{
// call controller
print(path);
String id=parentid.toString();
databaseHelper.parentprofileupdate(path, id);
// databaseHelper.parentprofileupdate(_profileImage, id);
}
}
Widget showpdatebutton() {
if(_profileImage!=null)
{
return OutlineButton(
child: Text('Update Profile Picture'),
onPressed: (){
_updateprofilepicture();
}
);
}
else
{
return Container();
}
}
}
My database helper class:
Future<ParentProfileUpdate> parentprofileupdate(String path,String id) async
{
Map mapValue;
var data;
final prefs = await SharedPreferences.getInstance();
final key = 'token';
final value = prefs.get(key ) ?? 0;
String myUrl = "$serverUrl/api/v1/upload_parent_image";
await http.post(myUrl,
headers: {
// 'Accept':'application/json',
"HttpHeaders.contentTypeHeader": "application/json",
'Authorization' : 'Bearer $value'
},
body: {
"photo" :path,
"id":id,
}).then((response) {
status = response.body.contains('error');
mapValue=json.decode(response.body);
var data = json.decode(response.body);
print(data);
});
}