How to display image automatically when it's picked (flutter) - firebase

when I upload an Image using firebase storage, it doesn't show in the screen until I do hot refresh. So the question is: How to show it automatically when I pick it either from the gallery or the camera? Thanks.
Codes:
late File file;
var imagePicker = ImagePicker();
var imgUrl;
var refStorage;
uploadPosterImage() async {
var pickedImage = await imagePicker.getImage(source: ImageSource.gallery);
if (pickedImage != null) {
setState(() {
file = File(pickedImage.path);
});
var imageName = basename(pickedImage.path);
var rand = Random().nextInt(10000000);
imageName = "$rand$imageName"; // random number + image name
refStorage = FirebaseStorage.instance.ref("items/$imageName");
await refStorage.putFile(file);
imgUrl = await refStorage.getDownloadURL();
}
}
------- and that's the code in the body:
Container(
margin: EdgeInsets.only(bottom: 10),
height: 230,
width: 160,
decoration: BoxDecoration(
border: Border.all(color: Colors.yellow),
borderRadius: BorderRadius.circular(20)),
child:
//imgUrl==null?
InkWell(
onTap: ()async{
await uploadPosterImage();
},
child: imgUrl == null? _icon : Image(image: NetworkImage(imgUrl),) )
),

Try below code hope its help to you.
File? imagePicked;
void cameraImage() async {
final picker = ImagePicker();
final pickedImage = await picker.pickImage(
source: ImageSource.camera,
);
final pickedImageFile = File(pickedImage!.path);
setState(() {
imagePicked = pickedImageFile;
});
Navigator.pop(context);
}
void gallaryImage() async {
final picker = ImagePicker();
final pickedImage = await picker.pickImage(
source: ImageSource.gallery,
);
final pickedImageFile = File(pickedImage!.path);
setState(() {
imagePicked = pickedImageFile;
});
Navigator.pop(context);
}
Your Widget:
Stack(
children: [
Container(
margin: EdgeInsets.all(8),
child: CircleAvatar(
radius: 71,
backgroundColor: Colors.black,
child: CircleAvatar(
backgroundColor: Colors.white,
radius: 69,
backgroundImage: imagePicked == null
? null
: FileImage(
imagePicked!,
),
),
),
),
Positioned(
left: 90,
top: 90,
child: RawMaterialButton(
fillColor: Theme.of(context).backgroundColor,
padding: EdgeInsets.all(10),
shape: CircleBorder(),
onPressed: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text(
'Choose Option',
),
content: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextButton.icon(
onPressed: cameraImage,
label: Text(
'Camera',
style: TextStyle(
color: Colors.black,
),
),
icon: Icon(
Icons.camera,
),
),
TextButton.icon(
onPressed: gallaryImage,
label: Text(
'Gallery',
style: TextStyle(
color: Colors.black,
),
),
icon: Icon(Icons.image),
),
],
),
),
);
},
);
},
child: Icon(
Icons.add_a_photo,
),
),
),
],
),
Your screen before image select:
Your screen after image select:

Related

Firebase List view is not displayed in real-time while adding data

I am storing Contact information on Firebase real-time DB after picking a contact from the phone.
When I add the data which is displayed using ListView and DataSnapshot the data is not refreshed in real-time until I restart the Activity. The ListView loads and displays all the data without any problem. How do I resolve this issue?
My screen looks like this:
Code for Screen:
import 'package:epicare/CaregiverClass.dart';
import 'package:epicare/Homepage.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_switch/flutter_switch.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:contact_picker/contact_picker.dart';
//Check contacts permission
Future<PermissionStatus> _getPermission() async {
final PermissionStatus permission = await Permission.contacts.status;
if (permission != PermissionStatus.granted &&
permission != PermissionStatus.denied) {
final Map<Permission, PermissionStatus> permissionStatus =
await [Permission.contacts].request();
return permissionStatus[Permission.contacts] ??
PermissionStatus.undetermined;
} else {
return permission;
}
}
class CaregiverScreen extends StatefulWidget {
#override
_CaregiverScreenState createState() => _CaregiverScreenState();
}
class _CaregiverScreenState extends State<CaregiverScreen> {
//Firebase
FirebaseAuth firebaseAuth = FirebaseAuth.instance;
final ref = FirebaseDatabase.instance.reference();
User cuser = FirebaseAuth.instance.currentUser;
final fb = FirebaseDatabase.instance.reference().child("User_data");
List <CaregiverList> list = List();
// Adding data into Firebase
void addData(String name, String number) {
print("Saving data to firebase");
ref.child('User_data').child(cuser.uid).child("caregivers").push().set({'Caregiver_Name': name, 'Caregiver_Number': number});
}
// Get location
Position _currentPosition;
String _currentAddress;
final Geolocator geolocator = Geolocator()..forceAndroidLocationManager;
#override
void initState() {
// Firebase
fb.child(cuser.uid).child("caregivers").once().then((DataSnapshot snapshot)
{
var data = snapshot.value;
list.clear();
data.forEach((key,value){
print(value['Caregiver_Name']);
CaregiverList contact_list = new CaregiverList(
name: value['Caregiver_Name'],
phone_number: value['Caregiver_Number'],
isActive: true,
key: key,
);
list.add(contact_list);
});
setState(() {
});
}
);
super.initState();
}
final ContactPicker _contactPicker = new ContactPicker();
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
//Size size = MediaQuery.of(context).size;
return Scaffold(
key: _scaffoldKey,
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: const Color(0xffE5E0A1),
elevation: 0,
centerTitle: true,
title: Text(
"Add Caregiver",
style: TextStyle(
fontSize: 15.0,
color: Colors.black,
fontFamily: 'Montserrat',
fontWeight: FontWeight.normal,
),
),
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.black,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return Homepage();
},
),
);
},
),
),
body: SingleChildScrollView(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 40),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
MaterialButton(
onPressed: () async {
final PermissionStatus permissionStatus =
await _getPermission();
if (permissionStatus == PermissionStatus.granted) {
//We can now access our contacts here
Contact contact = await _contactPicker.selectContact();
print("Contact name: ${contact.fullName}");
print("Contact number: ${contact.phoneNumber}");
List<String> num =
contact.phoneNumber.toString().split('(Work)');
print(num);
print(num[0]);
final pattern = RegExp('\\s+');
num[0].replaceAll(pattern, '');
num[0].replaceAll(new RegExp('-'),'');
addData(contact.fullName.toString(),num[0]);
} else {
//If permissions have been denied show standard cupertino alert dialog
showDialog(
context: context,
builder: (BuildContext context) =>
CupertinoAlertDialog(
title: Text('Permissions error'),
content: Text('Please enable contacts access '
'permission in system settings'),
actions: <Widget>[
CupertinoDialogAction(
child: Text('OK'),
onPressed: () =>
Navigator.of(context).pop(),
)
],
));
}
},
color: const Color(0xffd4d411),
textColor: Colors.white,
child: Icon(
Icons.add,
size: 32,
),
padding: EdgeInsets.all(3),
shape: CircleBorder(),
),
Text(
'Add a Caregiver',
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 13,
color: const Color(0xff000000),
height: 1.5384615384615385,
fontWeight: FontWeight.w600),
textHeightBehavior:
TextHeightBehavior(applyHeightToFirstAscent: false),
textAlign: TextAlign.left,
)
],
),
list.length == 0 ? Center(child: Text("Please add Caregivers"))
: ListView.separated(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
primary: false,
itemBuilder: (context, index) {
return _caregiverWidget(list[index].name,list[index].phone_number,list[index].isActive,list[index].key
);
},
separatorBuilder: (_, __) => Container(),
itemCount: list.length),
// _contact == null ? Container() : CaregiversList(_contact.fullName),
],
),
),
),
);
}
Widget _caregiverWidget( String name, String phone_number, bool isActive, String key
) {
print(name);
var c = name.split(' ');
print(c[0]);
var caregiver = c[0];
var output = getInitials(string: caregiver, limitTo: 1);
print(output);
return GestureDetector(
onLongPress: (){},
onTap: (){},
child: Card(
elevation: 0,
child: Container(
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 27),
child: Row(
//crossAxisAlignment: CrossAxisAlignment.center,
//mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
CircleAvatar(
radius: 24,
backgroundColor: const Color(0xffd4d411),
child: CircleAvatar(
radius: 22,
backgroundColor: Colors.white,
child: Text(
output,
style: TextStyle(
fontFamily: 'Segoe UI',
fontSize: 20,
color: const Color(0xff000000),
),
),
),
),
SizedBox(width: 19),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
caregiver,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 13,
color: const Color(0xff000000),
height: 1.5384615384615385,
fontWeight: FontWeight.w600),
textHeightBehavior:
TextHeightBehavior(applyHeightToFirstAscent: false),
textAlign: TextAlign.left,
),
isActive
? Text(
"Activated",
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 10,
color: const Color(0x80232425),
fontWeight: FontWeight.w500),
textAlign: TextAlign.left,
)
: Text(
"Disabled",
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 10,
color: const Color(0x80232425),
fontWeight: FontWeight.w500),
textAlign: TextAlign.left,
),
],
),
SizedBox(width: 143),
FlutterSwitch(
width: 40.0,
height: 20.0,
value: isActive,
toggleSize: 15,
borderRadius: 40.0,
padding: 2.0,
showOnOff: false,
activeColor: const Color(0xffd4d411),
activeToggleColor: Colors.white,
inactiveColor: const Color(0xffDDDBAF),
inactiveToggleColor: Colors.white,
onToggle: (value) {
print(value);
setState(() {
isActive = value;
// _careList.removeAt(index);
// _careList.insert(index, _caregiver);
});
},
),
],
),
),
),
);
}
String getInitials({String string, int limitTo}) {
var buffer = StringBuffer();
var split = string.split(' ');
for (var i = 0; i < (limitTo ?? split.length); i++) {
buffer.write(split[i][0]);
}
return buffer.toString();
}
}
The issue is that this part:
fb.child(cuser.uid).child("caregivers").once()..
is only getting the value once.
To se realtime updates you should either use a listener like here:
CollectionReference reference = Firestore.instance.collection('caregivers');
reference.snapshots().listen((querySnapshot) {
querySnapshot.documentChanges.forEach((change) {
// Do something with change
});
});
or a StreamBuilder like here:
StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('caregivers').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) return new Text('Loading...');
return new ListView(
children: snapshot.data.documents.map((DocumentSnapshot document) {
return new ListTile(
title: new Text(document['name']),
);
}).toList(),
);
},
);
for the RTDB the StreamBuilder would look like this:
StreamBuilder(
stream: _database.reference().child('caregivers').onValue,
builder: (context, event) {
if (event.hasData &&
!event.hasError &&
event.data.snapshot.value != null) {
DataSnapshot snapshot = event.data.snapshot;
}
})
the listener would be like:
_database.reference().child('caregivers').onValue.listen((event){
})
onValue will give you everytime the whole list so you need to empty it before you add again every item:
var data = event.snapshot.value;
list= List(); //Clear the list here
data.forEach((key, value) {
print(value['Caregiver_Name']);
CaregiverList contact_list = new CaregiverList(
name: value['Caregiver_Name'],
phone_number: value['Caregiver_Number'],
isActive: true,
key: key,
);
list.add(contact_list);
});

type 'Future<dynamic>' is not a subtype of type 'Widget?'

IM trying to call on Tap method, what I want now is change it to a future method because on Tap the method is not ready because im calling a firebase query . So heres first my method
where the onTap function is
child: InkWell(
onTap: () async {
setState(() {
israting = true;
});
},
child: israting
? buildBody(videos.data()['likes'], videos.data()['id'])
: Icon(
Icons.star,
size: 37,
color: videos.data()['likes'].contains(uid)
? Colors.yellow
: Colors.white,
),
),
So im giving the buildBody 2 parameters from a streambuilder
and then thats the function
buildBody(videoid, video) async {
if (videoid.contains(uid)) {
await FirebaseFirestore.instance
.collection("videos")
.doc(video)
.collection("uservotes")
.doc(uid)
.get()
.then((value) {
votefromfirebase = value.data()["rating"];
});
return Container(
child: Stack(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(3, 7, 0, 0),
child: Align(
alignment: Alignment.topLeft,
child: RatingBarIndicator(
rating: votefromfirebase,
itemBuilder: (context, index) => InkWell(
child: Icon(
Icons.star,
color: Colors.amber,
),
),
itemCount: 5,
itemSize: 31.0,
direction: Axis.horizontal,
),
),
),
Align(
alignment: Alignment.topRight,
child: TextButton(
onPressed: () {
print(video);
letuservoting = true;
setState(() {
_userRating = 0.0;
israting = false;
});
dislike(idovvideo, _userRating);
},
child: Text(
"Clear",
style: TextStyle(color: Colors.white, fontSize: 20),
),
),
),
],
));
} else {
return Container(
child: Stack(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(3, 7, 0, 0),
child: Align(
alignment: Alignment.topLeft,
child: RatingBarIndicator(
rating: _userRating,
itemBuilder: (context, index) => InkWell(
onTap: () {
setState(() {
_userRating = index + 1.toDouble();
});
likevideo(video, _userRating);
},
child: Icon(
Icons.star,
color: Colors.amber,
),
),
itemCount: 5,
itemSize: 31.0,
direction: Axis.horizontal,
),
),
),
Align(
alignment: Alignment.topRight,
child: TextButton(
onPressed: () {
letuservoting = true;
setState(() {
_userRating = 0.0;
israting = false;
});
dislike(idovvideo, _userRating);
},
child: Text(
"Clear",
style: TextStyle(color: Colors.white, fontSize: 20),
),
),
),
],
),
);
}
}
buildprofile(String url) {
return Container(
width: 50,
height: 50,
child: Stack(
children: [
Positioned(
left: (50 / 2) - (50 / 2),
child: Container(
width: 50,
height: 50,
padding: EdgeInsets.all(1),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(25),
),
child: Container(
child: ClipRRect(
borderRadius: BorderRadius.circular(60),
child: Container(
height: 110,
width: 110,
decoration: BoxDecoration(
color: Colors.white,
),
child: url != null && url != "profilepictureer"
? Image.network(
url,
fit: BoxFit.cover,
)
: Image.asset(
'assets/profilepictureer.png') // Your widget is here when image is no available.
),
),
decoration: new BoxDecoration(
shape: BoxShape.circle,
border: new Border.all(color: Colors.black, width: 4)),
),
),
),
],
),
);
}
}
At the moment im getting this error
The following _TypeError was thrown building:
type 'Future<dynamic>' is not a subtype of type 'Widget?'
When the exception was thrown, this was the stack
#0 _VideopageofcurrentuserState.build.<anonymous closure>.<anonymous closure> (package:wichtigdenyady/taking%20videos/currentuservideos.dart:310:47)
#1 SliverChildBuilderDelegate.build
package:flutter/…/widgets/sliver.dart:455
#2 SliverMultiBoxAdaptorElement._build
package:flutter/…/widgets/sliver.dart:1201
#3 SliverMultiBoxAdaptorElement.performRebuild.processElement
package:flutter/…/widgets/sliver.dart:1145
#4 Iterable.forEach (dart:core/iterable.dart:257:30)
The error throws in the onTap function
The buildBody function cannot be an async function.
You should move the call to Firebase out of this function and use the result of it in state, instead.
An async function always returns a Future. Because the return type isn't defined, it assumes it will return a Future<dynamic>. If you defined the return type as Widget buildBody(videoid, video) async, the IDE would show an error.
In your onTap function, you can make the call:
onTap: () async {
setState(() {
israting = true;
});
if(!videos.data()['likes'].contains(uid)) return; // don't call firebase if uid is not in videoid
final value = await FirebaseFirestore.instance
.collection("videos")
.doc(video)
.collection("uservotes")
.doc(uid)
.get();
setState(() {
votefromfirebase = value.data()["rating"];
});
},
Next, change the buildBody function to a non-async function and check if votefromfirebase is in the state
Widget buildBody(videoid, video) {
if (votefromfirebase == null) {
return Container(); // return empty container, progress indicator, or anything else
}
// else return the normal body
return Container(
child: Stack(
// rest of this widget

How to validate image in flutter on pressing submit button?

My every textfield is getting validated. But if the image is not selected and I press submit. It successfully gets uploaded to firestore without an image. But I want to make it stop incase image is null. When i load image it gets display in buildGridView. I guess i need to apply logic somewhere here. That if buildGridView is null. Stop or something. How can i achieve it. Thanks
Widget AddPost() {
return Form(
key: _key,
autovalidate: _validate,
child: Padding(
padding: const EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0),
child: Column(
children: <Widget>[
_getPropertyTypeDropDown(),
_getPropertyTypeDetailDropDown(),
UploadPropertyImages(),
Container(
margin: EdgeInsets.only(left: 7),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
width: 200,
height: MediaQuery.of(context).size.height / 4,
//color: Colors.green,
child: buildGridView(),
),
RaisedButton(
child: Text("Submit"),
onPressed: () async {
if (_key.currentState.validate()) {
_key.currentState.save();
Alert(
context: context,
style: alertStyle,
type: AlertType.info,
title: "YEY !!",
desc: "Your Ad will be displayed soon.",
buttons: [
DialogButton(
child: Text(
"Thankyou",
style: TextStyle(color: Colors.white, fontSize: 20),
),
// onPressed: () => Navigator.pop(context),
color: Color.fromRGBO(0, 179, 134, 1.0),
radius: BorderRadius.circular(0.0),
),
],
).show();
await runMyFutureGetImagesReference();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RoleCheck()));
} else {
setState(() {
_validate = true;
});
}
},
textColor: Colors.black,
padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
splashColor: Colors.grey,
),
],
),
),
//_showSubmitButton(),
],
)),
);
}
Widget buildGridView() {
return GridView.count(
crossAxisCount: 3,
children: List.generate(images.length, (index) {
Asset asset = images[index];
print(asset.getByteData(quality: 100));
return Padding(
padding: EdgeInsets.all(8.0),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(15)),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.blueAccent, width: 2)),
child: AssetThumb(
asset: asset,
width: 300,
height: 300,
),
),
),
// ),
);
}),
);
}
Widget UploadPropertyImages() {
return Container(
child: Center(
child: Padding(
padding: const EdgeInsets.fromLTRB(10, 10, 10, 10),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
NiceButton(
width: 250,
elevation: 8.0,
radius: 52.0,
text: "Select Images",
background: Colors.blueAccent,
onPressed: () async {
List<Asset> asst = await loadAssets();
if (asst.length == 0) {
showInSnackBar("No images selected");
}
// SizedBox(height: 10,);
else {
showInSnackBar('Images Successfully loaded');
}
}),
],
),
)));
}
Widget build(BuildContext context) {
return Scaffold(
// backgroundColor: Colors.grey[600],
key: _scaffoldKey,
body: Container(
padding: EdgeInsets.all(16.0),
child: Form(
child: ListView(
shrinkWrap: true,
children: <Widget>[
Center(
child: Text(
"Post New Ad",
style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold),
),
),
AddPost(),
Padding(
padding: EdgeInsets.fromLTRB(0, 0, 0, 16),
),
], //:TODO: implement upload pictures
),
),
),
);
}
Future<List<Asset>> loadAssets() async {
List<Asset> resultList = List<Asset>();
String error = "No error Detected";
try {
resultList = await MultiImagePicker.pickImages(
maxImages: 10,
enableCamera: true,
selectedAssets: images,
cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"),
materialOptions: MaterialOptions(
actionBarColor: "#abcdef",
actionBarTitle: "Upload Image",
allViewTitle: "All Photos",
useDetailsView: false,
selectCircleStrokeColor: "#000000",
),
);
print(resultList.length.toString() + "it is result list");
/* print((await resultList[0].getThumbByteData(122, 100)));
print((await resultList[0].getByteData()));
print((await resultList[0].metadata));*/
print("loadAssets is called");
} on Exception catch (e) {
error = e.toString();
print(error.toString() + "on catch of load assest");
}
By default Image Picker field is not a form element. You can pick a plugin to do so for your application. Here I am adding one. Please include it and it will give you the scope to validate the picked image as your requirements.
https://pub.dev/packages/image_picker_form_field
You will have to include it in pubspec.yaml and you are ready to use the widget it provides. Just use that like below:
ImagePickerFormField(
child: Container(
height: 40,
child: Center(child: Text("Select Photo")),
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(8)),
border: Border.all(
color: Theme.of(context).disabledColor, width: 1)),
),
previewEnabled: true,
autovalidate: true,
context: context,
onSaved: (File value) {
print("on saved called");
},
validator: (File value) {
if (value == null)
return "Please select a photo!";
else return null; },
initialValue: null, //File("some source")
)

FLUTTER Profile picture disappears when user leaves page

Please guys I really need help with this, I implemented an upload profile picture in my user profile page, everything works fine, the only problem is that the uploaded image disappears immediately when the user navigate away from this screen and come back to this same particular screen.
Looking forward to you awesome folks response, Thanks
This is the code that handles file selected and picture upload
class _UserProfileState extends State<UserProfile> {
DocumentSnapshot userDoc;
File _image;
String _uploadedFileURL;
Future chooseFile() async {
await ImagePicker.pickImage(source: ImageSource.gallery).then((image) {
setState(() {
_image = image;
});
});
uploadImage(_image);
}
Future<String> uploadImage(var imageFile) async {
StorageReference ref = FirebaseStorage.instance
.ref()
.child('chats/${Path.basename(_image.path)}}');
StorageUploadTask uploadTask = ref.putFile(imageFile);
var dowurl = await (await uploadTask.onComplete).ref.getDownloadURL();
_uploadedFileURL = dowurl.toString();
return _uploadedFileURL;
}
This is my user profile page screen
#override
Widget build(BuildContext context) {
var firebaseUser = FirebaseAuth.instance.currentUser;
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection('user_profile')
.doc(firebaseUser.uid)
.snapshots(),
builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
}
userDoc = snapshot.data;
return SafeArea(
child: Scaffold(
floatingActionButton: FloatingActionButton(
child: Icon(
Icons.edit,
color: Colors.white,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return EditUserProfile(userData: userDoc);
},
),
);
},
),
body: SafeArea(
child: Container(
padding: EdgeInsets.only(top: 10),
child: Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: IconButton(
onPressed: () {
Navigator.pushNamed(context, Homepage.id);
},
icon: Icon(
Icons.arrow_back,
color: Colors.white,
size: 30,
),
),
),
GestureDetector(
onTap: chooseFile,
child: Stack(
children: [
CircleAvatar(
radius: 70,
backgroundColor: Colors.transparent,
child: Container(
child: _uploadedFileURL == null
? ImageBeforeUpload(
image: _image, //This shows immediately when user chooses an image
// onTap: chooseFile,
)
: ImageUploaded(
uploadedFileURL: _uploadedFileURL // //This shows when image has been uploaded successfully but disappears when user leaves page and come back to this page
),
),
),
Positioned(
bottom: 0,
right: 0,
child: CircleAvatar(
backgroundColor: Colors.white60,
radius: 25,
child: IconButton(
onPressed: chooseFile,
icon: Icon(Icons.edit, color: Colors.blueGrey),
),
),
)
],
),
),
SizedBox(
height: 10,
),
IntrinsicHeight(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
userDoc.data()['nickname'] ?? '',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w900),
),
VerticalDivider(
thickness: 3,
width: 20,
color: Colors.white,
),
Text(
userDoc.data()['age'] ?? '',
style: TextStyle(
color: Colors.white,
),
),
],
),
),
Padding(
padding: const EdgeInsets.all(20.0),
child: Card(
child: Column(
children: [
ListTile(
leading: Icon(
Icons.person,
size: 40,
),
title: Text("About me"),
isThreeLine: false,
dense: true,
subtitle: Text(userDoc.data()['aboutMe'] ?? ''),
trailing: Icon(Icons.arrow_right),
)
],
),
),
),
Expanded(
child: Container(
width: 400,
child: ListView(
children: [
ProfileListTile(
leading: Icons.phone_in_talk,
title: 'Phone Number',
subtitle: userDoc.data()['mobile'] ?? '',
),
ProfileListTile(
leading: Icons.add_location,
title: 'Current Location',
subtitle: userDoc.data()['location'] ?? '',
),
ProfileListTile(
leading: FontAwesomeIcons.heartbeat,
title: 'Relationship Status',
subtitle: userDoc.data()['maritalStatus'] ?? '',
),
ProfileListTile(
leading: Icons.people,
title: 'Gender',
subtitle: userDoc.data()['gender'] ?? '',
),
ProfileListTile(
leading: Icons.looks,
title: 'Interested In',
subtitle: userDoc.data()['interestedIn'] ?? '',
),
// Padding(
// padding: const EdgeInsets.symmetric(
// horizontal: 50.0, vertical: 10),
// child: Row(
// mainAxisAlignment:
// MainAxisAlignment.spaceBetween,
// children: [
// Column(
// children: [
// IconButton(
// icon: Icon(Icons.phone,
// color: Colors.white),
// onPressed: null),
// Text(
// 'Call Me',
// style: klistTileTitle,
// ),
// ],
// ),
// Column(
// children: [
// IconButton(
// icon: Icon(Icons.message,
// color: Colors.white),
// onPressed: null),
// Text(
// 'Message',
// style: klistTileTitle,
// )
// ],
// ),
// Column(
// children: [
// IconButton(
// icon: FaIcon(
// FontAwesomeIcons.whatsapp,
// color: Colors.white,
// ),
// onPressed: () async {}),
// Text('Whatsapp', style: klistTileTitle)
// ],
// ),
// ],
// ),
// )
],
),
),
),
],
),
),
),
),
);
},
);
And finally this are the classes that handles what to display picture upload was success.
class ImageUploaded extends StatelessWidget {
ImageUploaded({this.uploadedFileURL});
final String uploadedFileURL;
#override
Widget build(BuildContext context) {
return CircleAvatar(
radius: 80,
child: ClipOval(
child: uploadedFileURL != null
? Image.network(uploadedFileURL,
height: 200, width: 200, fit: BoxFit.fill)
: Image.asset('assets/avatar_profile.jpg'),
),
);
}
}
class ImageBeforeUpload extends StatelessWidget {
ImageBeforeUpload({this.image});
final File image;
#override
Widget build(BuildContext context) {
return GestureDetector(
child: CircleAvatar(
radius: 70,
child: ClipOval(
child: image != null
? Image.asset(image.path,
height: 200, width: 200, fit: BoxFit.fill)
: Image.asset('assets/avatar_profile.jpg'),
),
),
);
}
}

How to perform CRUD operations with BLoC pattern?

I was learning on flutter how to perform CRUD operations using BLoC pattern, I saw a tutorial online and try to apply it. C,R,U are OK, but deletion is not working. this is the source code.
Please Help !
file todo_bloc.dart
import 'package:zencartos/models/todo.dart';
import 'package:zencartos/repository/todo_repository.dart';
class TodoBloc {
//Get instance of the Repository
final _todoRepository = TodoRepository();
final _todoController = StreamController<List<Todo>>.broadcast();
get todos => _todoController.stream;
TodoBloc() {
getTodos();
}
getTodos({String query}) async {
_todoController.sink.add(await _todoRepository.getAllTodos(query: query));
}
addTodo(Todo todo) async {
await _todoRepository.insertTodo(todo);
getTodos();
}
updateTodo(Todo todo) async {
await _todoRepository.updateTodo(todo);
getTodos();
}
deleteTodoById(int id) async {
_todoRepository.deleteTodoById(id);
getTodos();
}
dispose() {
_todoController.close();
}
}
DAO Page todo_dao.dart
import 'package:zencartos/database/database.dart';
import 'package:zencartos/models/todo.dart';
class TodoDao {
final dbProvider = DatabaseProvider.dbProvider;
Future<int> createTodo(Todo todo) async{
final db = await dbProvider.database;
var result = db.insert(todoTABLE, todo.toDatabaseJson());
return result;
}
Future<List<Todo>> getTodos({List<String> columns, String query})
async{
final db = await dbProvider.database;
List<Map<String, dynamic>> result;
if (query != null){
if (query.isNotEmpty)
result = await db.query(todoTABLE, columns: columns, where: 'description LIKE ?', whereArgs: ["%$query%"]);
} else {
result = await db.query(todoTABLE, columns: columns);
}
List<Todo> todos = result.isNotEmpty
? result.map((item)=> Todo.fromDatabaseJson(item)).toList()
: [];
return todos;
}
//Update Todo record
Future<int> updateTodo(Todo todo) async{
final db = await dbProvider.database;
var result = await db.update(todoTABLE, todo.toDatabaseJson(),
where: "id = ?", whereArgs: [todo.id]);
return result;
}
//Delete Todo records
Future<int> deleteTodo(int id) async{
final db = await dbProvider.database;
var result = await db.delete(todoTABLE, where: 'id = ?', whereArgs: [id]);
return result;
}
}
Database Page database.dart
import 'dart:io';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
final todoTABLE = 'Todo';
class DatabaseProvider {
static final DatabaseProvider dbProvider = DatabaseProvider();
Database _database;
Future<Database> get database async {
if (_database != null) return _database;
_database = await createDatabase();
return _database;
}
createDatabase() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, "ReactiveTodo");
var database = await openDatabase(path, version: 1, onCreate: initDB, onUpgrade: onUpgrade);
return database;
}
void onUpgrade(Database database, int oldVersion, int newVersion){
if (newVersion > oldVersion){}
}
void initDB(Database database, int version) async{
await database.execute("CREATE TABLE $todoTABLE ("
"id INTEGER PRIMARY KEY, "
"description TEXT, "
"is_done INTEGER "
")");
}
}
Model page todo.dart
class Todo{
int id;
String description;
bool isDone = false;
Todo({this.id, this.description, this.isDone = false});
factory Todo.fromDatabaseJson(Map<String, dynamic> data) => Todo(
id: data['data'],
description: data['description'],
isDone: data['is_done'] == 0 ? false : true,
);
Map<String, dynamic> toDatabaseJson() => {
"id": this.id,
"description": this.description,
"is_done": this.isDone == false ? 0 : 1,
};
}
View page home_Page2.dart
import 'package:flutter/services.dart';
import 'package:zencartos/bloc/todo_bloc.dart';
import 'package:zencartos/models/todo.dart';
class HomePage2 extends StatelessWidget {
HomePage2({Key key, this.title}) : super(key: key);
final TodoBloc todoBloc = TodoBloc();
final String title;
//Allows Todo card to be dismissable horizontally
final DismissDirection _dismissDirection = DismissDirection.horizontal;
#override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark.copyWith(
statusBarColor: Colors.white,
systemNavigationBarColor: Colors.white,
systemNavigationBarIconBrightness: Brightness.dark,
statusBarBrightness: Brightness.dark));
return Scaffold(
resizeToAvoidBottomPadding: false,
body: SafeArea(
child: Container(
color: Colors.white,
padding:
const EdgeInsets.only(left: 2.0, right: 2.0, bottom: 2.0),
child: Container(
//This is where the magic starts
child: getTodosWidget()))),
bottomNavigationBar: BottomAppBar(
color: Colors.white,
child: Container(
decoration: BoxDecoration(
border: Border(
top: BorderSide(color: Colors.grey, width: 0.3),
)),
child: Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
IconButton(
icon: Icon(
Icons.menu,
color: Colors.indigoAccent,
size: 28,
),
onPressed: () {
//just re-pull UI for testing purposes
todoBloc.getTodos();
}),
Expanded(
child: Text(
"Todo",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w600,
fontFamily: 'RobotoMono',
fontStyle: FontStyle.normal,
fontSize: 19),
),
),
Wrap(children: <Widget>[
IconButton(
icon: Icon(
Icons.search,
size: 28,
color: Colors.indigoAccent,
),
onPressed: () {
_showTodoSearchSheet(context);
},
),
Padding(
padding: EdgeInsets.only(right: 5),
)
])
],
),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButton: Padding(
padding: EdgeInsets.only(bottom: 25),
child: FloatingActionButton(
elevation: 5.0,
onPressed: () {
_showAddTodoSheet(context);
},
backgroundColor: Colors.white,
child: Icon(
Icons.add,
size: 32,
color: Colors.indigoAccent,
),
),
));
}
void _showAddTodoSheet(BuildContext context) {
final _todoDescriptionFormController = TextEditingController();
showModalBottomSheet(
context: context,
builder: (builder) {
return new Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: new Container(
color: Colors.transparent,
child: new Container(
height: 230,
decoration: new BoxDecoration(
color: Colors.white,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(10.0),
topRight: const Radius.circular(10.0))),
child: Padding(
padding: EdgeInsets.only(
left: 15, top: 25.0, right: 15, bottom: 30),
child: ListView(
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextFormField(
controller: _todoDescriptionFormController,
textInputAction: TextInputAction.newline,
maxLines: 4,
style: TextStyle(
fontSize: 21, fontWeight: FontWeight.w400),
autofocus: true,
decoration: const InputDecoration(
hintText: 'I have to...',
labelText: 'New Todo',
labelStyle: TextStyle(
color: Colors.indigoAccent,
fontWeight: FontWeight.w500)),
validator: (String value) {
if (value.isEmpty) {
return 'Empty description!';
}
return value.contains('')
? 'Do not use the # char.'
: null;
},
),
),
Padding(
padding: EdgeInsets.only(left: 5, top: 15),
child: CircleAvatar(
backgroundColor: Colors.indigoAccent,
radius: 18,
child: IconButton(
icon: Icon(
Icons.save,
size: 22,
color: Colors.white,
),
onPressed: () {
final newTodo = Todo(
description:
_todoDescriptionFormController
.value.text);
if (newTodo.description.isNotEmpty) {
/*Create new Todo object and make sure
the Todo description is not empty,
because what's the point of saving empty
Todo
*/
todoBloc.addTodo(newTodo);
//dismisses the bottomsheet
Navigator.pop(context);
}
},
),
),
)
],
),
],
),
),
),
),
);
});
}
void _showTodoSearchSheet(BuildContext context) {
final _todoSearchDescriptionFormController = TextEditingController();
showModalBottomSheet(
context: context,
builder: (builder) {
return new Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: new Container(
color: Colors.transparent,
child: new Container(
height: 230,
decoration: new BoxDecoration(
color: Colors.white,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(10.0),
topRight: const Radius.circular(10.0))),
child: Padding(
padding: EdgeInsets.only(
left: 15, top: 25.0, right: 15, bottom: 30),
child: ListView(
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextFormField(
controller: _todoSearchDescriptionFormController,
textInputAction: TextInputAction.newline,
maxLines: 4,
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.w400),
autofocus: true,
decoration: const InputDecoration(
hintText: 'Search for todo...',
labelText: 'Search *',
labelStyle: TextStyle(
color: Colors.indigoAccent,
fontWeight: FontWeight.w500),
),
validator: (String value) {
return value.contains('#')
? 'Do not use the # char.'
: null;
},
),
),
Padding(
padding: EdgeInsets.only(left: 5, top: 15),
child: CircleAvatar(
backgroundColor: Colors.indigoAccent,
radius: 18,
child: IconButton(
icon: Icon(
Icons.search,
size: 22,
color: Colors.white,
),
onPressed: () {
/*This will get all todos
that contains similar string
in the textform
*/
todoBloc.getTodos(
query:
_todoSearchDescriptionFormController
.value.text);
//dismisses the bottomsheet
Navigator.pop(context);
},
),
),
)
],
),
],
),
),
),
),
);
});
}
Widget getTodosWidget() {
return StreamBuilder(
stream: todoBloc.todos,
builder: (BuildContext context, AsyncSnapshot<List<Todo>> snapshot) {
return getTodoCardWidget(snapshot);
},
);
}
Widget getTodoCardWidget(AsyncSnapshot<List<Todo>> snapshot) {
if (snapshot.hasData) {
return snapshot.data.length != 0
? ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, itemPosition) {
Todo todo = snapshot.data[itemPosition];
final Widget dismissibleCard = new Dismissible(
background: Container(
child: Padding(
padding: EdgeInsets.only(left: 10),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
"Deleting",
style: TextStyle(color: Colors.white),
),
),
),
color: Colors.redAccent,
),
onDismissed: (direction) {
todoBloc.deleteTodoById(todo.id);
},
direction: _dismissDirection,
key: new ObjectKey(todo),
child: Card(
shape: RoundedRectangleBorder(
side: BorderSide(color: Colors.grey[200], width: 0.5),
borderRadius: BorderRadius.circular(5),
),
color: Colors.white,
child: ListTile(
leading: InkWell(
onTap: () {
//Reverse the value
todo.isDone = !todo.isDone;
todoBloc.updateTodo(todo);
},
child: Container(
//decoration: BoxDecoration(),
child: Padding(
padding: const EdgeInsets.all(15.0),
child: todo.isDone
? Icon(
Icons.done,
size: 26.0,
color: Colors.indigoAccent,
)
: Icon(
Icons.check_box_outline_blank,
size: 26.0,
color: Colors.tealAccent,
),
),
),
),
title: Text(
todo.description,
style: TextStyle(
fontSize: 16.5,
fontFamily: 'RobotoMono',
fontWeight: FontWeight.w500,
decoration: todo.isDone
? TextDecoration.lineThrough
: TextDecoration.none),
),
)),
);
return dismissibleCard;
},
)
: Container(
child: Center(
//this is used whenever there 0 Todo
//in the data base
child: noTodoMessageWidget(),
));
} else {
return Center(
child: loadingData(),
);
}
}
Widget loadingData() {
todoBloc.getTodos();
return Container(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(),
Text("Loading...",
style: TextStyle(fontSize: 19, fontWeight: FontWeight.w500))
],
),
),
);
}
Widget noTodoMessageWidget() {
return Container(
child: Text(
"Start adding Todo...",
style: TextStyle(fontSize: 19, fontWeight: FontWeight.w500),
),
);
}
dispose() {
todoBloc.dispose();
}
}
repository page todo_repository.dart
import 'package:zencartos/models/todo.dart';
class TodoRepository {
final todoDao = TodoDao();
Future getAllTodos({String query}) => todoDao.getTodos(query: query);
Future insertTodo(Todo todo) => todoDao.createTodo(todo);
Future updateTodo(Todo todo) => todoDao.updateTodo(todo);
Future deleteTodoById(int id) => todoDao.deleteTodo(id);
//We are not going to use this in the demo
//Future deleteAllTodos() => todoDao.deleteAllTodos();
}
In your todo_bloc.dart, your delete method should be:
deleteTodoById(int id) async {
await _todoRepository.deleteTodoById(id);
getTodos();
}

Resources