Related
I've created a flutter project that show a staggeredgridview of images from firestore database. Once i click on one of the images it shows that image. What i want is a download button thats saves the image to my device. Ath the moment I've just used pop.
I've read some about the path provider package but i can't figure out how to implement this in the code. Perhaps there is a better solution?
StaggeredGridView Page
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:proj/screens/home/instafull.dart';
import 'dart:async';
import 'package:proj/services/auth.dart';
import 'package:proj/shared/constants.dart';
class Instapage extends StatefulWidget {
#override
_InstapageState createState() => _InstapageState();
}
class _InstapageState extends State<Instapage> {
final AuthService _auth = AuthService();
StreamSubscription<QuerySnapshot> subscription;
List<DocumentSnapshot> wallpaperlist;
final CollectionReference collectionReference = FirebaseFirestore.instance.collection('mediapost');
#override
void initState() {
// TODO: implement initState
super.initState();
subscription = collectionReference.snapshots().listen((datasnapshot) {
setState(() {
wallpaperlist = datasnapshot.docs;
});
});
}
#override
void dispose() {
subscription?.cancel();
// TODO: implement dispose
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: bas,
body: wallpaperlist != null?
StaggeredGridView.countBuilder(
padding: const EdgeInsets.fromLTRB(10, 8, 10, 0),
crossAxisCount: 4,
itemCount: wallpaperlist.length,
itemBuilder: (context, index){
String imgPath = wallpaperlist[index].get('img');
return new Material(
elevation: 8,
borderRadius: BorderRadius.all(Radius.circular(8.0)),
child: InkWell(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => InstaFull(imgPath: imgPath))),
child: Hero(
tag: imgPath,
child: FadeInImage(
image: NetworkImage(imgPath),
fit: BoxFit.cover,
placeholder: AssetImage('assets/wally2.jpg'),
),
),
),
);
},
staggeredTileBuilder: (index) => StaggeredTile.count(2, index.isEven?2:3),
mainAxisSpacing: 8,
crossAxisSpacing: 8,
): Center(
child: CircularProgressIndicator(),
),
);
}
}
Picture Page
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class InstaFull extends StatelessWidget {
String imgPath;
InstaFull({this.imgPath});
final LinearGradient backgroundGradient = LinearGradient(
colors: [Color(0x10000000), Color(0x30000000)],
begin: Alignment.topLeft,end: Alignment.bottomRight);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SizedBox.expand(
child: Stack(
children: [
Align(
alignment: Alignment.center,
child: Hero(
tag: imgPath,
child: Image.network(imgPath),
),
),
Align(
alignment: Alignment.topCenter,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
leading: IconButton(
icon: Icon(Icons.close,
color: Colors.black,
),
onPressed: () => Navigator.of(context).pop(),
),
),
],
),
),
Align(
alignment: Alignment.bottomCenter,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('Download')),
],),
)
],
),
),
);
}
}
You can use gallery_saver
Install it and enable this permissions:
iOS
Add the following keys to your Info.plist file, located in <project root>/ios/Runner/Info.plist:
NSPhotoLibraryUsageDescription - describe why your app needs permission for the photo library. This is called Privacy - Photo Library Usage Description in the visual editor.
Android
Android
android.permission.WRITE_EXTERNAL_STORAGE - Permission for usage of external storage
Official example of gallery_saver:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:gallery_saver/gallery_saver.dart';
import 'package:image_picker/image_picker.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String firstButtonText = 'Take photo';
String secondButtonText = 'Record video';
double textSize = 20;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
color: Colors.white,
child: Column(
children: <Widget>[
Flexible(
flex: 1,
child: Container(
child: SizedBox.expand(
child: RaisedButton(
color: Colors.blue,
onPressed: _takePhoto,
child: Text(firstButtonText,
style:
TextStyle(fontSize: textSize, color: Colors.white)),
),
),
),
),
Flexible(
child: Container(
child: SizedBox.expand(
child: RaisedButton(
color: Colors.white,
onPressed: _recordVideo,
child: Text(secondButtonText,
style: TextStyle(
fontSize: textSize, color: Colors.blueGrey)),
),
)),
flex: 1,
)
],
),
),
));
}
void _takePhoto() async {
ImagePicker.pickImage(source: ImageSource.camera)
.then((File recordedImage) {
if (recordedImage != null && recordedImage.path != null) {
setState(() {
firstButtonText = 'saving in progress...';
});
GallerySaver.saveImage(recordedImage.path).then((String path) {
setState(() {
firstButtonText = 'image saved!';
});
});
}
});
}
void _recordVideo() async {
ImagePicker.pickVideo(source: ImageSource.camera)
.then((File recordedVideo) {
if (recordedVideo != null && recordedVideo.path != null) {
setState(() {
secondButtonText = 'saving in progress...';
});
GallerySaver.saveVideo(recordedVideo.path).then((String path) {
setState(() {
secondButtonText = 'video saved!';
});
});
}
});
}
void _saveNetworkVideo() async {
String path =
'https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4';
GallerySaver.saveVideo(path).then((bool success) {
setState(() {
print('Video is saved');
});
});
}
void _saveNetworkImage() async {
String path =
'https://image.shutterstock.com/image-photo/montreal-canada-july-11-2019-600w-1450023539.jpg';
GallerySaver.saveImage(path).then((bool success) {
setState(() {
print('Image is saved');
});
});
}
}
The only error I get here is for the code File selectedImage; and the error states "Non-nullable instance field 'selectedImage' must be initialized. Try adding an initializer expression, or a generative constructor that initializes it, or mark it 'late'.
Here is my code:
import 'dart:io';
import 'package:tennis_event_app/services/crud.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:random_string/random_string.dart';
class CreateBlog extends StatefulWidget {
#override
_CreateBlogState createState() => _CreateBlogState();
}
class _CreateBlogState extends State<CreateBlog> {
//
File selectedImage;
final picker = ImagePicker();
bool isLoading = false;
CrudMethods crudMethods = new CrudMethods();
Future getImage() async {
final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
if (pickedFile != null) {
selectedImage = File(pickedFile.path);
} else {
print('No image selected.');
}
});
}
Future<void> uploadBlog() async {
if (selectedImage != null) {
// upload the image
setState(() {
isLoading = true;
});
Reference firebaseStorageRef = FirebaseStorage.instance
.ref()
.child("blogImages")
.child("${randomAlphaNumeric(9)}.jpg");
final UploadTask task = firebaseStorageRef.putFile(selectedImage);
var imageUrl;
await task.whenComplete(() async {
try {
imageUrl = await firebaseStorageRef.getDownloadURL();
} catch (onError) {
print("Error");
}
print(imageUrl);
});
// print(downloadUrl);
Map<String, dynamic> blogData = {
"imgUrl": imageUrl,
"author": authorTextEditingController.text,
"title": titleTextEditingController.text,
"desc": descTextEditingController.text
};
crudMethods.addData(blogData).then((value) {
setState(() {
isLoading = false;
});
Navigator.pop(context);
});
// upload the blog info
}
}
//
TextEditingController titleTextEditingController =
new TextEditingController();
TextEditingController descTextEditingController = new TextEditingController();
TextEditingController authorTextEditingController =
new TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Create Blog"),
actions: [
GestureDetector(
onTap: () {
uploadBlog();
},
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Icon(Icons.file_upload)),
)
],
),
body: isLoading
? Container(
child: Center(
child: CircularProgressIndicator(),
))
: SingleChildScrollView(
child: Container(
margin: EdgeInsets.symmetric(horizontal: 16),
child: Column(
children: [
GestureDetector(
onTap: () {
getImage();
},
child: selectedImage != null
? Container(
height: 150,
margin: EdgeInsets.symmetric(vertical: 24),
width: MediaQuery.of(context).size.width,
child: ClipRRect(
borderRadius:
BorderRadius.all(Radius.circular(8)),
child: Image.file(
selectedImage,
fit: BoxFit.cover,
),
),
)
: Container(
height: 150,
decoration: BoxDecoration(
color: Colors.grey,
borderRadius:
BorderRadius.all(Radius.circular(8))),
margin: EdgeInsets.symmetric(vertical: 24),
width: MediaQuery.of(context).size.width,
child: Icon(
Icons.camera_alt,
color: Colors.white,
),
),
),
TextField(
controller: titleTextEditingController,
decoration: InputDecoration(hintText: "enter title"),
),
TextField(
controller: descTextEditingController,
decoration: InputDecoration(hintText: "enter desc"),
),
TextField(
controller: authorTextEditingController,
decoration:
InputDecoration(hintText: "enter author name"),
),
],
)),
),
);
}
}
I also get two warnings, but not sure if there is really a problem here. this is the warning for lines 37 and 118, "The operand can't be null, so the condition is always true."
Any help would be greatly appreciated, I have been stuck on this for two days!
It seems you're using null safety. So the problem is File selectedImage is marked as being not nullable, but you're not initializing it in the constructor. Try replacing it with File? selectedImage or late File selectedImage.
At lines 37 and 118 remove the ! as it is not necessary.
I suggest you to read https://flutter.dev/docs/null-safety as it is explained in great details.
I have a screen which shows list of customers using listview. Next when I click on a customer I want to show the notes(records) only of that particular customer(customerId) in next screen in listview. This is my code which should work fine but its not displaying anything. I have checked if noteDetails table contains data and it has. Can anyone tell where am I wrong or what code should i add more please.
main.dart
import 'package:flutter/material.dart';
import 'package:vers2cts/screens/user_login.dart';
void main() {
runApp(MyApp());
}
Map<int, Color> color ={50:Color.fromRGBO(170, 0, 95, .1),
100:Color.fromRGBO(170, 0, 95, .2),
200:Color.fromRGBO(170, 0, 95, .3),
300:Color.fromRGBO(170, 0, 95, .4),
400:Color.fromRGBO(170, 0, 95, .5),
500:Color.fromRGBO(170, 0, 95, .6),
600:Color.fromRGBO(170, 0, 95, .7),
700:Color.fromRGBO(170, 0, 95, .8),
800:Color.fromRGBO(170, 0, 95, .9),
900:Color.fromRGBO(170,0,95, 1),};
MaterialColor colorCustom = MaterialColor(0xFF880E4F, color);
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'NoteKeeper',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch:colorCustom,
primaryColor:colorCustom//primarySwatch: Colors.purple
),
home: UserLogin(),
);
}
}
Note_info.dart //This is the file where i want to display the notes of particular customer.
import 'dart:io';
import 'package:customer/models/CustomerNote.dart';
import 'package:customer/models/addCustomer.dart';
import 'package:customer/services/db_service.dart';
import 'package:customer/utils/database_helper.dart';
import 'package:flutter/material.dart';
import 'package:sqflite/sqflite.dart';
import 'New_Note.dart';
class Note_Info extends StatefulWidget{
final String appBarTitle;
final AddCustomer customer;
Note_Info(this. customer, this.appBarTitle);
#override
State<StatefulWidget> createState() {
return Note_InfoState(this. customer,this.appBarTitle);
}
}
class Note_InfoState extends State<Note_Info> {
DBService dbService = DBService();
List<CustomerNote> noteList;
int count = 0;
static final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
CustomerNote note=CustomerNote();
String appBarTitle;
AddCustomer customer;
Note_InfoState(this.customer, this.appBarTitle);
DateTime _date = DateTime.now();
TextEditingController custNameController = TextEditingController();
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
int customerId=customer.custId;
if (noteList == null) {
noteList = List<CustomerNote>();
updateListView();
}
TextStyle titleStyle = Theme.of(context).textTheme.subhead;
var height = MediaQuery.of(context).size.height;
custNameController.text = customer.custName;
return DefaultTabController(
length: 4,
child: Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(
Icons.add,
),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => NewNote(note)));
},
)
],
),
body: Container(
child: Column(
children: <Widget>[
TextField(controller: custNameController,
style: TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold),
textAlign: TextAlign.center),
Padding(
padding: const EdgeInsets.all(15.0),
child: Row(children: [
ImageProfile(customer.custPhoto),
Padding(
padding: const EdgeInsets.only(left: 30.0),
child: IconButton(
icon: Icon(
Icons.call,
color: Colors.green,
size: 45,
),
onPressed: () {
},
),
),
],),
),
SizedBox(
height: 50,
child: AppBar(
bottom: TabBar(
tabs: [
Tab(
text: "All",
),
Tab(
text: "Pending",
),
Tab(
text: "Cancelled",
),
Tab(
text: "Completed",
),
],
),
),
),
// create widgets for each tab bar here
Expanded(
child: TabBarView(
children: [
// first tab bar view widget
Container(
child: getNoteListView()
),
// second tab bar viiew widget
Container(
),
Container(
child: Center(
child: Text(
'Cancelled',
),
),
),
Container(
child: Center(
child: Text(
'Completed',
),
),
),
],
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 55.0,
width: 200,
child: RaisedButton(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
color: Theme
.of(context)
.primaryColorDark,
textColor: Colors.white,
child: Text('Save', textScaleFactor: 1.5,),
onPressed: () {
setState(() {
//_reset();
});
},
),
),
),
]
),
)
));
}
Widget ImageProfile(String fileName) {
return Center(
child: CircleAvatar(
radius: 80.0,
backgroundImage: fileName == null
?AssetImage('images/person_icon.jpg')
:FileImage(File(customer.custPhoto))),
);
}
ListView getNoteListView() {
TextStyle titleStyle = Theme.of(context).textTheme.subhead;
return ListView.builder(
itemCount: count,
itemBuilder: (BuildContext context, int position) {
return Card(
color: Colors.white,
elevation: 2.0,
child: ListTile(
title: Text(this.noteList[position].note, style: titleStyle,),
trailing: GestureDetector(
child: Icon(Icons.delete, color: Colors.grey,),
onTap: () {
},
),
onTap: () {
},
),
);
},
);
}
void updateListView() {
final Future<Database> dbFuture = DB.init();
dbFuture.then((database) {
int cid=customer.custId;
Future<List<CustomerNote>> noteListFuture = dbService.getCustomerNotes(cid);
noteListFuture.then((noteList) {
setState(() {
this.noteList = noteList;
this.count = noteList.length;
});
});
});
}
}
New_Note.dart //This is where new note is added in database successfully
import 'package:customer/models/CustomerNote.dart';
import 'package:customer/models/addCustomer.dart';
import 'package:customer/screens/Note_info.dart';
import 'package:customer/services/db_service.dart';
import 'package:customer/utils/form_helper.dart';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:table_calendar/table_calendar.dart';
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
import 'package:smooth_star_rating/smooth_star_rating.dart';
import 'package:intl/intl.dart';
class NewNote extends StatefulWidget{
final CustomerNote note;
NewNote(this. note);
final Function(Color) onChanged;
final double height;
final double width;
NewNote({
Key key,
this.onChanged,
this.height = 25,
this.width = 150,
this.label,
}) : super(key: key);*/
#override
State<StatefulWidget> createState() {
return New_NoteState(this.note);
}
}
class New_NoteState extends State<NewNote> with SingleTickerProviderStateMixin{
New_NoteState(this.note);
CustomerNote note=new CustomerNote();
AddCustomer customer=new AddCustomer();
TextEditingController NoteController=TextEditingController();
TextEditingController custNameController = TextEditingController();
DateTime _reminderDate = DateTime.now();
DBService dbService=new DBService();
SpeedDial _speedDial(){
return SpeedDial(
animatedIcon: AnimatedIcons.add_event,
animatedIconTheme: IconThemeData(size: 24.0),
backgroundColor: Colors.yellow,
curve: Curves.easeInCirc,
children: [
SpeedDialChild(
child: Icon(Icons.location_on,color: Colors.yellow,),
label: 'Add Location',
),
SpeedDialChild(
child: Icon(Icons.keyboard_voice),
//backgroundColor: Colors.yellow,
label: 'Add voice',
//labelBackgroundColor: Colors.yellow
),
SpeedDialChild(
child: Icon(Icons.attachment_outlined,color :Colors.redAccent),
label: 'Add File',
),
SpeedDialChild(
child: Icon(Icons.image,color: Colors.lightBlue,),
label: 'Add Image',
),
],
);
}
//for DropDownMenu
Color value=Colors.red;
final List<Color> colors = [
Colors.red,
Colors.blue,
Colors.green,
Colors.yellow,
Colors.pink,
Colors.purple,
Colors.brown,
];
bool isSwitched = false;
var textValue = 'Switch is OFF';
void toggleSwitch(bool value) {
if(isSwitched == false)
{
setState(() {
isSwitched = true;
this.note.remindOn = _reminderDate.toString();
});
}
else
{
setState(() {
isSwitched = false;
});
}
}
#override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
custNameController.text = customer.custName;
return WillPopScope(
onWillPop: () {
moveToLastScreen();
},
child: Scaffold(
appBar:AppBar(),
body:ListView(
children: <Widget>[
SizedBox(
height: 2.0,
),
TextField(controller: custNameController,
style: TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold),
textAlign: TextAlign.center),
Align(
alignment: Alignment.centerLeft,
child: Text("Add New",textAlign: TextAlign.left,
style: TextStyle(fontSize: 22,fontWeight: FontWeight.bold),),
),
SizedBox(
height: 2.0,
),
Divider(),
SizedBox(
height: 2.0,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: NoteController,
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide: const BorderSide(width: 2.0),)),
keyboardType: TextInputType.multiline,
minLines: 5,
maxLines: 5,
onChanged: (value) {
this.note.note = value;
},
),
),
TableCalendar(
selectedDayPredicate: (day) {
return isSameDay(_reminderDate, day);
},
onDaySelected: (selectedDay, focusedDay) {
setState(() {
_reminderDate = selectedDay;
});
},
focusedDay: DateTime.now(),
firstDay: DateTime.utc(2010, 10, 16),
lastDay: DateTime.utc(2030, 3, 14),),
SizedBox(
height: height*0.03,
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(//mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text("Remind me",style: TextStyle(fontSize: 20),),
Padding(
padding: const EdgeInsets.only(left:80.0),
child: Container(
child: Switch(
onChanged: toggleSwitch,
value: isSwitched,
),
),
],),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(mainAxisAlignment: MainAxisAlignment.start,
children:<Widget>[
Text("Priority",style: TextStyle(fontSize: 20.0),),
Padding(
padding: const EdgeInsets.only(left:20.0),
child: Container(
child: SmoothStarRating(
size: height=50.0,
allowHalfRating: false,
onRated: (value) {
this.note.priority=value;
print("rating value -> $value");
},
),
),
)]),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Row(mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text("Color",style: TextStyle(fontSize: 20),),
Padding(
padding: const EdgeInsets.only(left:80.0),
child: Container(
child: DropdownButton<Color>(
value: value,
onChanged: (color) {
setState(() => value = color);
},
items: colors.map((e) => DropdownMenuItem(
value: e,
child: Container(
width: 60.0,
color: e,
),
),
)
.toList(),
),
),
),
],),
),
SizedBox(
height: height*0.08,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 55.0,
width: 200,
child: RaisedButton(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
color: Theme.of(context).primaryColorDark,
textColor: Colors.white,
child: Text('Save',textScaleFactor: 1.5,),
onPressed: (){
setState(() {
_save();
});
},
),
),
),
],
),
floatingActionButton:_speedDial(),
));
}
void moveToLastScreen() {
Navigator.pop(context, true);
}
void _save() async {
moveToLastScreen();
note.custId=customer.custId;
note.date = DateFormat.yMMMd().format(DateTime.now());
int result;
if (note.id != null) { // Case 1: Update operation
result = await dbService.updateNote(note);
} else { // Case 2: Insert Operation
result = await dbService.insertNote(note);
}
if (result != 0) { // Success
FormHelper.showAlertDialog(context,'Status', 'Note Saved Successfully');
} else { // Failure
FormHelper.showAlertDialog(context,'Status', 'Problem Saving Note');
}
}
}
db_service.dart
Future<bool> insertCustomer(AddCustomer model) async {
await DB.init();
bool isSaved = false;
if (model != null) {
int inserted = await DB.insert(AddCustomer.table, model);
isSaved = inserted == 1 ? true : false;
}
return isSaved;
}
Future<List<Map<String, dynamic>>> getCustomerMapList() async {
await DB.init();
var result = await DB.query(AddCustomer.table);
return result;
}
Future<List<AddCustomer>> getCustomerList() async {
var CustomerMapList = await getCustomerMapList();
int count = CustomerMapList.length;
List<AddCustomer> customerList = List<AddCustomer>();
for (int i = 0; i < count; i++) {
customerList.add(AddCustomer.fromMap(CustomerMapList[i]));
}
return customerList;
}
Future<int> insertNote(CustomerNote note) async {
await DB.init();
var result = await DB.insert(CustomerNote.table, note);
return result;
}
Future<List<CustomerNote>> getCustomerNotes(int customer) async {
await DB.init();
var res = await DB.rawQuery("noteDetails WHERE custId = '$customer'");
int count = res.length;
List<CustomerNote> notelist = List<CustomerNote>();
for (int i = 0; i < count; i++) {
notelist.add(CustomerNote.fromMap(res[i]));
}
return notelist;
}
database_helper.dart
import 'dart:async';
import 'package:customer/models/model.dart';
import 'package:path/path.dart' as p;
import 'package:sqflite/sqflite.dart';
abstract class DB {
static Database _db;
static int get _version => 1;
static Future<Database> init() async {
if (_db != null) {
return _db;
}
try {
var databasesPath = await getDatabasesPath();
String _path = p.join(databasesPath, 'Customer.db');
_db = await openDatabase(_path, version: _version, onCreate: onCreate);
print('db location:'+_path);
} catch (ex) {
print(ex);
}
}
static void onCreate(Database db, int version) async {
await db.execute(
'CREATE TABLE userDetails (id INTEGER PRIMARY KEY AUTOINCREMENT, '
'firstName STRING, '
'lastName STRING, mobileNum STRING, emailId STRING, address String,'
'userType STRING,password STRING)');
await db.execute(
'CREATE TABLE customerDetails (custId INTEGER PRIMARY KEY AUTOINCREMENT, '
'custName STRING, '
'mobileNum STRING, company STRING, custPhoto STRING, showOnCall bool,'
'remindOn STRING,location STRING)');
await db.execute(
'CREATE TABLE noteDetails (noteId INTEGER PRIMARY KEY AUTOINCREMENT, '
'custId STRING, '
'custName STRING, date STRING, note STRING, remindOn STRING,'
'priority STRING,status STRING,attachment STRING)');
await db.execute(
'CREATE TABLE languagesKnown(custId INTEGER REFERENCES customerDetails(custId),'
' languages STRING,PRIMARY KEY(custId))');
}
static Future<List<Map<String, dynamic>>> query(String table) async =>
_db.query(table);
static Future<int> insert(String table, Model model) async =>
await _db.insert(table, model.toMap());
static Future<int> update(String table, Model model) async => await _db
.update(table, model.toMap(), where: 'id = ?', whereArgs: [model.id]);
static Future<int> delete(String table, Model model) async =>
await _db.delete(table, where: 'id = ?', whereArgs: [model.id]);
static Future<int> deleteCustomer(String table, Model model) async =>
await _db.delete(table, where: 'custId = ?', whereArgs: [model.custId]);
static Future<Batch> batch() async => _db.batch();
static Future<List<Map<String, dynamic>>> rawQuery(String table) async =>
_db.query(table);
}
people_list.dart // This is where list of customers is displayed and by clicking on a listtile i.e customer, Note_info opens
import 'package:customer/models/addCustomer.dart';
import 'package:customer/screens/Note_info.dart';
import 'package:customer/screens/User_Settings.dart';
import 'package:customer/screens/add_person.dart';
import 'package:customer/services/db_service.dart';
import 'package:customer/utils/database_helper.dart';
import 'package:customer/utils/form_helper.dart';
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:sqflite/sqflite.dart';
class People_List extends StatefulWidget{
#override
State<StatefulWidget> createState() {
return People_ListState();
}
}
class People_ListState extends State<People_List> with SingleTickerProviderStateMixin{
DBService dbService = DBService();
List<AddCustomer> customerList;
int count = 0;
static final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
var _isSelectedItemIndex;
#override
void initState() {
super.initState();
_searchQuery = new TextEditingController();
}
Widget _buildTitle(BuildContext context) {
var horizontalTitleAlignment =
Platform.isIOS ? CrossAxisAlignment.center : CrossAxisAlignment.start;
return new InkWell(
onTap: () => scaffoldKey.currentState.openDrawer(),
child: new Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: horizontalTitleAlignment,
children: <Widget>[
const Text(''),
],
),
),
);
}
#override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
if (customerList == null) {
customerList = List<AddCustomer>();
updateListView();
}
return Scaffold(
appBar: new AppBar(
),
body:getCustomerListView(),
floatingActionButton: FloatingActionButton(
onPressed: () {
navigateToCustomer(AddCustomer(), 'Add Person');
},
child: const Icon(Icons.add),
),
}
ListView getCustomerListView() {
TextStyle titleStyle = Theme.of(context).textTheme.subhead;
return ListView.builder(
itemCount: count,
itemBuilder: (BuildContext context, int position) {
var _imageFile=customerList[position].custPhoto;
return Card(
color: Colors.white,
elevation: 2.0,
child: ListTile(
leading: CircleAvatar(
backgroundImage: _imageFile==null?AssetImage('images/person_icon.jpg')
:FileImage(File(_imageFile.toString()))),
title: Text(this.customerList[position].custName, style: titleStyle,),
trailing: Icon(Icons.keyboard_arrow_right),
onTap: () {
navigateToDetail(this.customerList[position],'Edit ');
},
),
);
},
);
}
void navigateToDetail(AddCustomer customer, String title) async {
bool result = await Navigator.push(context, MaterialPageRoute(builder: (context) {
return Note_Info(customer, title);
}));
if (result == true) {
updateListView();
}
}
void updateListView() {
final Future<Database> dbFuture = DB.init();
dbFuture.then((database) {
Future<List<AddCustomer>> customerListFuture = dbService.getCustomerList();
customerListFuture.then((customerList) {
setState(() {
this.customerList = customerList;
this.count = customerList.length;
});
});
});
}
}
Finally I myself had to solve the problem. The problem was that where I was creating note and saving it in "note" table cust_id was not saved in the table. So I passed CustomerModel object and NoteModel object to New_Note(). Now its working fine
new_note.dart
class NewNote extends StatefulWidget{
final NoteModel note;
final CustomerModel customer;
NewNote(this.customer,this. note);
#override
State<StatefulWidget> createState() {
//return New_NoteState(this.customer);
return New_NoteState(this.customer,this.note);
}
class New_NoteState extends State<NewNote> with SingleTickerProviderStateMixin{
New_NoteState(this.customer,this.note);
NoteModel note=new NoteModel();
CustomerModel customer=new CustomerModel();
}
void _save() async {
note.cust_id=customer.cust_id;
...
}
I would like to navigate to new screen just after upload completed.
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
if (_uploadTask.isComplete)
Text('Yükleme Tamamlandı',
style: TextStyle(
color: Colors.greenAccent,
height: 2,
fontWeight: FontWeight.w500,
fontSize: 30)
),
Here is the detailed codes :
/// Widget to capture and crop the image
class DocUploadScreen extends StatefulWidget {
createState() => _DocUploadScreenState();
}
class _DocUploadScreenState extends State<DocUploadScreen>
{
/// Active image file
File _imageFile;
/// Select an image via gallery or camera
Future<void> _pickImage(ImageSource source) async {
File selected = await ImagePicker.pickImage(source:
source);
setState(() {
_imageFile = selected;
});
}
/// Remove image
void _clear() {
setState(() => _imageFile = null);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("FÖY YÜKLEME EKRANI"),
),
bottomNavigationBar: BottomAppBar(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: <Widget>[
IconButton(
icon: Icon(
Icons.photo_camera,
size: 30,
),
onPressed: () =>
_pickImage(ImageSource.camera),
color: Colors.blue,
),
IconButton(
icon: Icon(
Icons.photo_library,
size: 30,
),
onPressed: () =>
_pickImage(ImageSource.gallery),
color: Colors.red,
),
],
),
),
body: ListView(
children: <Widget>[
if (_imageFile != null) ...[
Container(
padding: EdgeInsets.all(32), child:
Image.file(_imageFile)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
FlatButton(
color: Colors.blueAccent,
textColor: Colors.white,
child: Icon(Icons.refresh),
onPressed: _clear,
),
],
),
Padding(
padding: const EdgeInsets.all(32),
child: Uploader(
file: _imageFile,
),
)
]
],
),
);
}
}
class Uploader extends StatefulWidget {
final File file;
Uploader({Key key, this.file}) : super(key: key);
createState() => _UploaderState();
}
class _UploaderState extends State<Uploader> {
final FirebaseStorage _storage =
FirebaseStorage(storageBucket: 'gs://emo-is0.appspot.com');
StorageUploadTask _uploadTask;
_startUpload() {
String filePath = 'faturalar/${DateTime.now()}.png';
setState(() {
_uploadTask =
_storage.ref().child(filePath).putFile(widget.file);
});
}
#override
Widget build(BuildContext context) {
if (_uploadTask != null) {
return StreamBuilder<StorageTaskEvent>(
stream: _uploadTask.events,
builder: (context, snapshot) {
var event = snapshot?.data?.snapshot;
double progressPercent = event != null
? event.bytesTransferred / event.totalByteCount
: 0;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
if (_uploadTask.isComplete)
Text('Yükleme Tamamlandı',
style: TextStyle(
color: Colors.greenAccent,
height: 2,
fontWeight: FontWeight.w500,
fontSize: 30)
),
if (_uploadTask.isPaused)
FlatButton(
child: Icon(Icons.play_arrow, size: 50),
onPressed: _uploadTask.resume,
),
if (_uploadTask.isInProgress)
FlatButton(
child: Icon(Icons.pause, size: 50),
onPressed: _uploadTask.pause,
),
LinearProgressIndicator(value:
progressPercent),
Text(
'${(progressPercent * 100).toStringAsFixed(2)}
% ',
style: TextStyle(fontSize: 50),
),
]);
});
}
else {
return FlatButton.icon(
color: Colors.blue,
textColor: Colors.white,
label: Text('Sunucuya Yükle'),
icon: Icon(Icons.cloud_upload),
onPressed: _startUpload);
}
}
}
Just after upload process completed there should be navigation to new screen. Here I tried these codes, I can not achieve to handle navigation. So Where should I put code so there will be navigation just after upload process completed.
I think you do the upload is separate function (you could provide us with more code here, how you do the upload), so make that function async and wait for it to complete with "await" in front of it. After that call a function that navigates to the new page.
Your code should look like this:
Future _startUpload() {
String filePath = 'faturalar/${DateTime.now()}.png';
setState(() {
_uploadTask =
_storage.ref().child(filePath).putFile(widget.file);
});
}
void upload() async{
await _startUpload;
if (_uploadTask != null) {
navigateToNewPage();
} else {
print('Upload went wrong');
}
}
void navigateToNewPage() {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondPage()),
);
}
I want to navigate just after text Yükleme Tamamlandı seen...
I've not worked with this package but I'd try it like this instead:
_startUpload() async {
String filePath = 'föyler/${DateTime.now()}.png';
StorageUploadTask uploadTask = _storage.ref().child(filePath).putFile(widget.file);
StorageTaskSnapshot taskSnapshot = await uploadTask.onComplete;
navigateToNewPage();
}
Ill try and provide as much code as possible. (mainly regarding the image ill be using "other data" instead of posting non needed code besides the image)
So in my app I have a File image; provider and im having issues with getting to display it on my app. Im unable to pass the File image path into firebase and its causing my app to crash when I try Fetching the data from firebase. Ill try providing as much code as possible.
Here is my provider:
import 'dart:io';
class AddCar {
// other data
File image;
AddCar({
// other data
this.image,
});
}
Here is my provider code:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:io';
import '../add_ons/add_car.dart';
List<AddCar> _cars = [];
class Cars with ChangeNotifier {
List<AddCar> get cars {
return [..._cars];
}
Future<void> fetchAndSetCars() async {
const url = 'https://mycustomlink.firebaseio.com/cars.json';
try {
final response = await http.get(url);
final extractedData = json.decode(response.body) as Map<String, dynamic>;
var loadedCars = extractedData
.map<String, AddCar>((carId, carData) => MapEntry(
carId,
AddCar(
// other data
image: File(carData['image']),
)))
.values
.toList();
_cars = loadedCars;
print(extractedData);
print(loadedCars);
notifyListeners();
} catch (error) {
throw (error);
}
}
AddCar findById(String id) {
return _cars.firstWhere((carProd) => carProd.id == id);
}
void addCar(AddCar car) {
const url = 'https://mycustomlink.firebaseio.com/cars.json';
http.post(
url,
body: json.encode({
// other data
'image': car.image.toString(),
}),
);
final newCar = AddCar(
// other data
image: car.image,
);
_cars.insert(0, newCar);
notifyListeners();
}
}
here is my form where the user enters data for it to be displayed:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_app/app_localization.dart';
import 'package:google_fonts_arabic/fonts.dart';
import 'package:provider/provider.dart';
import 'package:file_picker/file_picker.dart';
import 'package:image_picker/image_picker.dart';
import 'dart:io';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart' as syspaths;
import '../add_ons/add_car.dart';
import '../providers/car_provider.dart';
import '../drawer/drawer.dart';
import '../screens/cars_screen.dart';
import '../app_localization.dart';
class CreateCar extends StatefulWidget {
static const routeName = '/create-car';
#override
_CreateCarState createState() => _CreateCarState();
}
class _CreateCarState extends State<CreateCar> {
final _name = TextEditingController();
final _price = TextEditingController();
final _address = TextEditingController();
String img;
static Future<String> fileToB64(File f) async {
List<int> imageBytes = f.readAsBytesSync();
return base64Encode(
imageBytes,
);
}
Future<void> _takePicture() async {
final imageFile = await ImagePicker.pickImage(
source: ImageSource.gallery,
);
fileToB64(data.image).then((d) {
setState(() {
img = d; //base64Decode(d);
});
});
}
final _form = GlobalKey<FormState>();
int currStep = 0;
static AddCar data = new AddCar(
id: null,
date: DateTime.now(),
sponsNum: '',
);
void _saveForm() {
final isValid = _form.currentState.validate();
if (!isValid) {
return;
}
_form.currentState.save();
Provider.of<Cars>(context, listen: false).addCar(data);
Navigator.of(context).pushNamed(CarsScreen.routeName);
print('this works');
}
#override
Widget build(BuildContext context) {
List<Step> steps = [
Step(
title: Text(
AppLocalizations.of(context).createTabTitle,
),
isActive: true,
state: StepState.indexed,
content: Column(
children: <Widget>[
// other data
],
),
),
Step(
title: Text(
AppLocalizations.of(context).createCarDetails,
),
isActive: true,
state: StepState.indexed,
content: Column(
children: <Widget>[
// other data
Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 25.0),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Theme.of(context).primaryColor),
borderRadius: BorderRadius.circular(50.0),
),
child: FlatButton(
child: Text(AppLocalizations.of(context).createAddImages),
onPressed: _takePicture,
),
),
)
],
)
],
),
),
];
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
AppLocalizations.of(context).createCarPageTitle,
textAlign: TextAlign.center,
style: TextStyle(
fontFamily: ArabicFonts.Tajawal,
package: 'google_fonts_arabic',
),
),
actions: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
IconButton(
icon: Icon(Icons.save),
onPressed: _saveForm,
),
IconButton(
icon: Icon(Icons.arrow_forward),
onPressed: () {
Navigator.of(context).pop();
},
)
],
),
],
),
drawer: MyDrawer(),
body: Row(
children: <Widget>[
Form(
key: _form,
child: Expanded(
child: Stepper(
steps: steps,
type: StepperType.vertical,
currentStep: this.currStep,
onStepContinue: () {
setState(() {
if (currStep < steps.length - 1) {
currStep = currStep + 1;
} else {
// currStep = 0;
}
});
},
onStepCancel: () {
setState(() {
if (this.currStep > 0) {
this.currStep = this.currStep - 1;
} else {
this.currStep = 0;
}
});
},
onStepTapped: (step) {
setState(() {
currStep = step;
});
},
),
),
),
],
),
);
}
}
which is later passed into my "CarItem" that will display my code:
import 'package:flutter/material.dart';
import 'package:google_fonts_arabic/fonts.dart';
import '../icons/MyIcons.dart';
import 'dart:io';
import '../details/car_details.dart';
import '../app_localization.dart';
class CarItem extends StatelessWidget {
final File image;
CarItem(
this.image,
);
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Theme.of(context).primaryColor, width: 2.0),
),
),
child: Column(
children: <Widget>[
Container(
decoration: BoxDecoration(
color: Color.fromARGB(255, 245, 245, 245),
),
child: Padding(
padding: const EdgeInsets.fromLTRB(17.0, 4.0, 17.0, 4.0),
child: Row(
textDirection: TextDirection.rtl,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
// other data
],
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width * 0.35,
height: MediaQuery.of(context).size.width * 0.35,
child: GestureDetector(
child: Image.file(
image,
fit: BoxFit.fill,
),
onTap: () {
Navigator.of(context).pushNamed(
MyCarDetails.routeName,
arguments: id,
);
},
),
),
Container(
width: MediaQuery.of(context).size.width * 0.65,
margin: EdgeInsets.all(0),
padding: const EdgeInsets.fromLTRB(22.0, 5.0, 22.0, 0),
child: Column(
children: <Widget>[
// other data
],
),
),
],
),
),
],
),
],
),
);
}
}
this code gets called by a list that will call the code and display it in my app:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:google_fonts_arabic/fonts.dart';
import '../providers/car_provider.dart';
import '../widget/car_item.dart';
class CarsList extends StatefulWidget {
#override
_CarsListState createState() => _CarsListState();
}
class _CarsListState extends State<CarsList> {
#override
Widget build(BuildContext context) {
final carsData = Provider.of<Cars>(context);
final car = carsData.cars;
return car.isEmpty
? Center(
child: Text(
'no data yet available',
style: TextStyle(
fontFamily: ArabicFonts.Tajawal,
fontWeight: FontWeight.bold,
package: 'google_fonts_arabic',
),
))
: ListView.builder(
padding: const EdgeInsets.only(bottom: 47.0),
itemCount: car.length,
itemBuilder: (ctx, i) => CarItem(
// other data
car[i].image,
),
);
}
}
this is the error i keep getting when It tries to display fetched data:
════════ Exception caught by widgets library ═══════════════════════════════════
The following NoSuchMethodError was thrown building CarItem(dirty, dependencies: [_LocalizationsScope-[GlobalKey#31697], MediaQuery, _InheritedTheme]):
The method '+' was called on null.
Receiver: null
Tried calling: +("25")
User-created ancestor of the error-causing widget was
ListView
lib\home_parts\cars_area.dart:49
When the exception was thrown, this was the stack
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
#1 CarItem.build
package:flutter_app/widget/car_item.dart:151
#2 StatelessElement.build
package:flutter/…/widgets/framework.dart:4009
#3 ComponentElement.performRebuild
package:flutter/…/widgets/framework.dart:3941
#4 Element.rebuild
package:flutter/…/widgets/framework.dart:3738
...
════════════════════════════════════════════════════════════════════════════════
How can I fix this? is the issue in how im passing the data to firebase and displaying it on my app?