I'm using Flutter, I need to save image in SQLite as BLOB, then display it in my page.
I did it as String and it works fine but not image with 1.5 MB size, the app get unhanded exception, I tried to do it as blob but I could not find any tutorial anywhere.
My model:
import 'package:flutter/services.dart';
const String tablePersonal = 'personal_info';
class PersonalFields {
static final List<String> values = [
id,
name,
logo,
];
static const String id = '_id';
static const String name = 'name';
static const String logo = 'logo';
}
class PersonalInfoModel {
int? id;
final String name;
final Uint8List? logo;
PersonalInfoModel({
this.id,
required this.name,
this.logo,
});
PersonalInfoModel copy({
int? id,
String? name,
Uint8List? logo,
}) =>
PersonalInfoModel(
id: id ?? this.id,
name: name ?? this.name,
logo: logo ?? this.logo,
);
static PersonalInfoModel fromJson(Map<String, Object?> json) =>
PersonalInfoModel(
id: json[PersonalFields.id] as int?,
name: json[PersonalFields.name] as String,
logo: json[PersonalFields.logo] as Uint8List?,
);
Map<String, dynamic> toJson() => {
PersonalFields.id: id,
PersonalFields.name: name,
PersonalFields.logo: logo,
};
}
SQL Helper: after create the table I just make insert null record to save the id = 1 so that I will just update the record. That is means the table will only get one record.
batch.execute('''
CREATE TABLE IF NOT EXISTS $tablePersonal
(
${PersonalFields.id} $idType,
${PersonalFields.name} $textType,
${PersonalFields.logo} $blobType
)
''');
batch.execute('''
INSERT INTO $tablePersonal
(
${PersonalFields.name}
)
VALUES
(
''
)
''');
//read personal info
Future<List<PersonalInfoModel>> getPesonalInfo() async {
var db = await instanace.database;
final result = await db.query(tablePersonal);
return result.map((json) => PersonalInfoModel.fromJson(json)).toList();
}
Future<int> updatePersonalInfo(PersonalInfoModel personalInfoModel) async {
final db = await instanace.database;
return db.update(
tablePersonal,
personalInfoModel.toJson(),
where: '${PersonalFields.id} = ?',
whereArgs: [personalInfoModel.id],
);
}
My Page:
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image_picker/image_picker.dart';
import 'package:ledger/database/sql_helper.dart';
import 'package:ledger/l10n/app_local.dart';
import 'package:ledger/models/personal_info_model.dart';
class PersonalInfoPage extends StatefulWidget {
const PersonalInfoPage({Key? key}) : super(key: key);
#override
State<PersonalInfoPage> createState() => _PersonalInfoPageState();
}
class _PersonalInfoPageState extends State<PersonalInfoPage> {
final _formKey = GlobalKey<FormState>();
final TextEditingController _nameController = TextEditingController();
double boxWidth = 10;
double boxHieght = 10;
XFile? xImage;
var bytes;
final ImagePicker _picker = ImagePicker();
late List<PersonalInfoModel> personalList;
late PersonalInfoModel existPersonal;
bool isLoading = true;
#override
void initState() {
super.initState();
getPersonalInfo();
}
Future pickImage() async {
try {
xImage = await _picker.pickImage(source: ImageSource.gallery);
if (xImage == null) return;
final imagePath = File(xImage!.path);
bytes = imagePath;
setState(() {});
} on PlatformException catch (e) {
print('Failed to pick image: $e');
}
}
Future getPersonalInfo() async {
final data = await SQLHelper.instanace.getPesonalInfo();
setState(() {
personalList = data;
getData();
isLoading = false;
});
}
getData() {
existPersonal = personalList.firstWhere((element) => element.id == 1);
_nameController.text = existPersonal.name;
bytes = existPersonal.logo;
}
Future updatePersonalInfo(PersonalInfoModel personalInfoModel) async {
await SQLHelper.instanace.updatePersonalInfo(personalInfoModel);
getPersonalInfo();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(AppLocal.loc.personal_info),
actions: [
IconButton(
onPressed: () {
PersonalInfoModel personalInfoModel = PersonalInfoModel(
id: 1,
name: _nameController.text,
logo: bytes);
updatePersonalInfo(personalInfoModel);
},
icon: const Icon(Icons.save_as_outlined),
),
],
),
body: isLoading
? const Center(child: CircularProgressIndicator())
: SingleChildScrollView(
child: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 5.0),
child: Form(
key: _formKey,
child: Column(
children: [
SizedBox(height: boxHieght),
TextFormField(
controller: _nameController,
decoration: InputDecoration(
filled: true,
labelText: AppLocal.loc.name,
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(5.0),
),
),
),
),
],
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextButton(
onPressed: () {
print('xxxxxx');
pickImage();
},
child: Text('from Gallary'),
),
],
),
Container(
color: Colors.grey.shade100,
height: 150,
width: 150,
child: bytes != null
? Image.memory(bytes)
: Image.asset('assets/logo.png'),
),
],
),
),
);
}
}
Here is how you can convert it into a blob and save it to SQLite
Future pickImage(ImageSource source) async {
try {
final image = await ImagePicker.pickImage(source: source);
final imagePath = File(image.path);
List<int> bytes = await image.readAsBytes();
String base64 = base64Encode(bytes);// here it is. Save it to sqflite
} on PlatformException catch (e) {
print(e);
}
}
for getting from SQLite
String blobImageFromSqflite; //get from sqflite
Uint8List _bytesImage = Base64Decoder().convert(blobImageFromSqflite);
to display it;
Image.memory(
_bytesImage,
);
Related
I used Share_Prefereces library so I want to save date of adding Item. I tried many ways but
I always get the errors: E/flutter ( 2786): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: type 'Null' is not a subtype of type 'DateTime'
and the second error is: Unhandled Exception: Converting object to an encodable object failed: Instance of 'Shopping'
so please help me
the code of Date file is:
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';
class Shopping {
String item;
int price;
DateTime date;
Shopping({required this.item, required this.price, required this.date});
Map<String, dynamic> toJson() {
return {
'item': item,
'price': price,
'date': date,
};
}
}
class ItemData extends ChangeNotifier {
List<Shopping> listOfItem = [];
void addItem(Shopping shopping) {
listOfItem.add(shopping);
notifyListeners();
}
void editItem(Shopping shopping, int itemIndex) {
listOfItem[itemIndex] = shopping;
notifyListeners();
}
void deleteItem(int itemIndex) {
listOfItem.removeAt(itemIndex);
notifyListeners();
}
saveData() async {
SharedPreferences pref = await SharedPreferences.getInstance();
List<String> tempList = [];
for (int i = 0; i < listOfItem.length; i++) {
tempList.add(jsonEncode(listOfItem[i]));
}
pref.remove("itemList");
pref.setStringList("itemList", tempList);
}
loadData() async {
SharedPreferences pref = await SharedPreferences.getInstance();
if (pref.getStringList('itemList') != null) {
List<String> tempList = pref.getStringList('itemList')!;
for (int i = 0; i < tempList.length; i++) {
Map<String, dynamic> temp = jsonDecode(tempList[i]);
addItem(
Shopping(
item: temp['item'],
price: temp['price'],
date: temp['date'],
),
);
}
}
}
}
and the code of adding Item, price and date is:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:goods_and_price/shopping_data.dart';
import 'package:provider/provider.dart';
class AddItem extends StatelessWidget {
AddItem({Key? key}) : super(key: key);
TextEditingController userInputItem = TextEditingController();
TextEditingController userInputPrice = TextEditingController();
#override
Widget build(BuildContext context) {
var provider = Provider.of<ItemData>(context, listen: true);
DateTime date = DateTime.now();
return Scaffold(
appBar: AppBar(
title: const Text('Add Item'),
centerTitle: true,
backgroundColor: const Color(0xFF00899C),
),
body: ListView(
physics: const BouncingScrollPhysics(),
children: [
Padding(
padding: const EdgeInsets.all(10.0),
child: TextField(
controller: userInputItem,
decoration: InputDecoration(
hintText: 'Item',
labelText: 'Item',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
prefixIcon: const Icon(
Icons.shopping_cart,
color: Color(0xFF00899C),
)),
maxLines: null,
),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: TextField(
controller: userInputPrice,
decoration: InputDecoration(
hintText: 'Price',
labelText: 'Price',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
prefixIcon: const Icon(
Icons.attach_money,
color: Color(0xFF00899C),
)),
maxLines: null,
),
),
const SizedBox(
height: 10,
),
CupertinoButton(
padding: const EdgeInsets.all(0),
pressedOpacity: 0.5,
child: Container(
height: 50,
width: 120,
decoration: BoxDecoration(
color: const Color(0xFF00899C),
borderRadius: BorderRadius.circular(10)),
child: const Center(
child: Text(
'Add Item',
style: TextStyle(color: Colors.white),
),
),
),
onPressed: () async {
Shopping newItem = Shopping(
item: userInputItem.text,
price: int.parse(userInputPrice.text),
date: date,
);
provider.addItem(newItem);
provider.saveData();
Navigator.pop(context);
},
),
],
),
);
}
}
I don't recommend using DateTime, because it takes a certain amount of work to use in different languages, I find it easier to use String.
I couldn't simulate the error on my machine, but I made an example, I hope it helps.
To create class I like to use this site https://javiercbk.github.io/json_to_dart/
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:zoociadoleite_app/global/my_app.dart';
class TesteScreen extends StatefulWidget {
const TesteScreen({Key key}) : super(key: key);
#override
State<TesteScreen> createState() => _TesteScreenState();
}
class Shopping {
String item;
int price;
String date;
Shopping({this.item, this.price, this.date});
Shopping.fromJson(Map<String, dynamic> json) {
item = json['item'];
price = json['price'];
date = json['date'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['item'] = this.item;
data['price'] = this.price;
data['date'] = this.date;
return data;
}
}
class LocalStorage {
Future<String> get(String item) async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString(item);
}
Future<bool> set(String item, dynamic data) async {
final prefs = await SharedPreferences.getInstance();
return prefs.setString(item, json.encode(data));
}
Future<bool> remove(String item) async {
final prefs = await SharedPreferences.getInstance();
return prefs.remove(item);
}
}
class _TesteScreenState extends State<TesteScreen> {
final formatDate = new DateFormat.yMMMMd('pt_BR');
Future<List<Shopping>> _future;
List<Shopping> list = [];
load() async {
String data = await LocalStorage().get("Shopping");
if (data != null) {
List<dynamic> lista = json.decode(data) as List;
list = lista.map((shopping) => Shopping.fromJson(shopping)).toList();
}
_future = Future.value(list);
setState(() {});
}
#override
void initState() {
super.initState();
load();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<List<Shopping>>(
future: _future,
builder: (context, snapshot) {
if (snapshot.hasData)
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
Shopping shopping = snapshot.data[index];
return ListTile(
title: Text(shopping.item),
subtitle: Text("${shopping.price}"),
trailing: Text("${formatDate.format(DateTime.parse(shopping.date))}"),
);
},
);
return CircularProgressIndicator();
},
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
list.add(Shopping(item: "test_${list.length + 1}", price: list.length + 1, date: DateTime.now().toString()));
_future = Future.value(list);
LocalStorage().set("Shopping", list);
setState(() {});
},
child: const Icon(Icons.add),
),
);
}
}
fetchData is my function from where I call the API and put the data into an object, which is UserModel Somehow, it is working perfectly. But I want to put my data into a list because I want to make a search function where I can search by name. Look into my code, which will help you to understand.
Future<UserModel>? futureUser;
Future<UserModel>? fetchData() async {
final response =
await http.get(Uri.parse('https://reqres.in/api/users?page=2'));
print('This is Response: $response');
if (response.statusCode == 200) {
// this is a way which I've tried already and it works
// return UserModel.fromJson(jsonDecode(response.body));
} else {
return throw Exception('Failed to load album');
}
}
But I want to put the data into a list and make the search available. Like if i put some name like r+a+b+b+i, it will show the matching name from the API.
I have tried this but I am not clear about the consepet. I am not familiar with how to manipulate the JSON data in a list or object or how to convert an object into a list.
List<UserModel>? userList = [];
Future<UserModel>? fetchData() async {
final response =
await http.get(Uri.parse('https://reqres.in/api/users?page=2'));
print('This is Response: $response');
if (response.statusCode == 200) {
// var result= UserModel.fromJson(jsonDecode(response.body));
// print('this is result $userList');
return userList.add(UserModel.fromJson(jsonDecode(response.body)));
// this is an way which i tried already and its works
// return UserModel.fromJson(jsonDecode(response.body));
} else {
return throw Exception('Failed to load album');
}
}
This is my whole code
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:learning_1ui_6228/utilities/app_colors.dart';
import 'package:learning_1ui_6228/utilities/helper.dart';
import 'package:learning_1ui_6228/utilities/widgets/app_line.dart';
import 'package:learning_1ui_6228/utilities/widgets/list_tile_widget.dart';
import 'package:learning_1ui_6228/views/nav_pages/profile_page.dart';
import 'package:http/http.dart' as http;
import '../model/UserModel.dart';
class FirstScreen extends StatefulWidget {
const FirstScreen({Key? key}) : super(key: key);
#override
State<FirstScreen> createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen> {
Future<UserModel>? futureUser;
TextEditingController textController = TextEditingController();
// List<UserModel> userList=[];
#override
void initState() {
// searchedList = userList;
futureUser = fetchData();
super.initState();
}
List<UserModel>? userList = [];
Future<UserModel>? fetchData() async {
final response =
await http.get(Uri.parse('https://reqres.in/api/users?page=2'));
print('This is Response: $response');
if (response.statusCode == 200) {
// var result= UserModel.fromJson(jsonDecode(response.body));
// print('this is result $userList');
return userList.add(UserModel.fromJson(jsonDecode(response.body)));
// this is an way which i tried already and its works
// return UserModel.fromJson(jsonDecode(response.body));
} else {
return throw Exception('Failed to load album');
}
}
List<UserModel> searchedList = [];
void searchUser(String enteredData){
print('entered word + ${enteredData}');
searchedList = [];
for(int i=0; i<userList!.length; i++){
if(userList[i].data![i].firstName!.toLowerCase().contains(enteredData.toLowerCase())){
searchedList.add(userList![i]);
}
}
}
#override
Widget build(BuildContext context) {
//print('user list data + $searchedList');
return SafeArea(
child: Scaffold(
backgroundColor: Color(0xfff8f8fa),
body: Column(
children: [
//1st Section
Container(
height: HelperClass.h250,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: AppColors.gradientColor,
),
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(HelperClass.r10),
bottomLeft: Radius.circular(HelperClass.r10))),
child: Column(
children: <Widget>[
//Text and cross button
Container(
margin: EdgeInsets.only(
left: HelperClass.w10,
right: HelperClass.w10,
top: HelperClass.h20),
height: HelperClass.h50,
// color: Colors.red,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
child: IconButton(
onPressed: () {},
icon: Icon(
Icons.clear,
color: Colors.white,
size: 30,
))),
Expanded(
child: Container(
margin: EdgeInsets.only(right: 30),
alignment: Alignment.center,
// color: Colors.lightBlueAccent,
child: Text(
'Search',
style: TextStyle(
fontSize: HelperClass.t25,
fontWeight: FontWeight.bold,
color: Colors.white),
),
),
),
],
),
),
SizedBox(
height: HelperClass.h25,
),
//Search Bar
Container(
margin: EdgeInsets.only(
left: HelperClass.w10, right: HelperClass.w10),
//color: Colors.amber,
height: HelperClass.h70,
width: double.infinity,
child: TextField(
controller: textController,
onChanged: (name) {
setState(() {
searchUser(name);
});
},
decoration: InputDecoration(
prefix: Icon(
Icons.search,
size: 26,
),
suffix: IconButton(
onPressed: () {
setState(() {
textController.clear();
searchedList = userList;
});
},
icon: Icon(
Icons.clear,
size: 26,
),
),
hintText: 'Search',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(3),
borderSide: BorderSide.none,
),
filled: true,
fillColor: Colors.white,
),
),
),
],
),
),
// List View
Expanded(
child: FutureBuilder<UserModel>(
future: futureUser,
builder: (context, snapshot){
if(snapshot.hasData){
return ListView.builder(
itemCount: snapshot.data!.data!.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.all(10),
child: Column(
children: [
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProfilePage(
userName:snapshot.data!.data![index].firstName??'',
followers: snapshot.data!.data![index].id.toString(),
address: snapshot.data!.data![index].email.toString(),
following: snapshot.data!.data![index].lastName.toString(),
imageUrl: snapshot.data!.data![index].avatar.toString(),
),
));
},
child: ListTileWidgets(
following: snapshot.data!.data![index].lastName.toString(),
address: snapshot.data!.data![index].email.toString(),
imageUrl:snapshot.data!.data![index].avatar.toString(),
name: snapshot.data!.data![index].firstName??'',
followersCount:
'Followers: ${snapshot.data!.data![index].id.toString()}',
iconWidget: Icon(
Icons.person_add_alt_outlined,
color: Colors.red,
size: 25,
),
),
),
AppLine(
paddingLeft: 10,
paddingRight: 10,
heightLine: 1,
lineColor: Colors.grey),
],
),
);
},
);
}
else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return Center(child: CircularProgressIndicator());
}),
),
],
),
),
);
}
}
This is my UserModel class
import 'dart:convert';
UserModel userModelFromJson(String str) => UserModel.fromJson(json.decode(str));
String userModelToJson(UserModel data) => json.encode(data.toJson());
class UserModel {
UserModel({
this.page,
this.perPage,
this.total,
this.totalPages,
this.data,
this.support,});
UserModel.fromJson(dynamic json) {
page = json['page'];
perPage = json['per_page'];
total = json['total'];
totalPages = json['total_pages'];
if (json['data'] != null) {
data = [];
json['data'].forEach((v) {
data?.add(Data.fromJson(v));
});
}
support = json['support'] != null ? Support.fromJson(json['support']) : null;
}
int? page;
int? perPage;
int? total;
int? totalPages;
List<Data>? data;
Support? support;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['page'] = page;
map['per_page'] = perPage;
map['total'] = total;
map['total_pages'] = totalPages;
if (data != null) {
map['data'] = data?.map((v) => v.toJson()).toList();
}
if (support != null) {
map['support'] = support?.toJson();
}
return map;
}
}
Support supportFromJson(String str) => Support.fromJson(json.decode(str));
String supportToJson(Support data) => json.encode(data.toJson());
class Support {
Support({
this.url,
this.text,});
Support.fromJson(dynamic json) {
url = json['url'];
text = json['text'];
}
String? url;
String? text;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['url'] = url;
map['text'] = text;
return map;
}
}
Data dataFromJson(String str) => Data.fromJson(json.decode(str));
String dataToJson(Data data) => json.encode(data.toJson());
class Data {
Data({
this.id,
this.email,
this.firstName,
this.lastName,
this.avatar,});
Data.fromJson(dynamic json) {
id = json['id'];
email = json['email'];
firstName = json['first_name'];
lastName = json['last_name'];
avatar = json['avatar'];
}
int? id;
String? email;
String? firstName;
String? lastName;
String? avatar;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['id'] = id;
map['email'] = email;
map['first_name'] = firstName;
map['last_name'] = lastName;
map['avatar'] = avatar;
return map;
}
}
this is my api link
https://reqres.in/api/users?page=2
No need to add UserModel to list.
change this
class _FirstScreenState extends State<FirstScreen> {
UserModel? usermodel;
List<Data?> searchResult= [];
change your fetch data . this will return UserModel as result.
Future<UserModel?> fetchData() async {
final response =
await http.get(Uri.parse('https://reqres.in/api/users?page=2'));
print('This is Response: $response');
if (response.statusCode == 200) {
return UserModel.fromJson(jsonDecode(response.body));
} else {
return throw Exception('Failed to load album');
}
}
create init function to set your initial data
void initFunction() async {
UserModel data = await fetchData(); // you have to await until get the response
//then setState to local variable so it can display to widget
// if you skip this , your usermodel is null
setState ({
usermodel = data ;
});
}
then in your initState
#override
void initState() {
initFunction();
super.initState();
}
usermodel.data consist of data user.
to then you can apply logic to search user from the list.
void searchUser(String enteredData){
List<Data?> temp = [];
for(int i=0; i<usermodel.data.length; i++){
if(enteredData.toLowerCase() == usermodel.data[i].firstName.toLowerCase()){
temp.add(usermodel.data[i];
}
}
// you need to setState again
setState({
searchResult = temp;
});
}
last in you can acces the data in userModel
#override
Widget build(BuildContext context) {
//print('user list data + $searchedList');
return SafeArea(
child: Scaffold(
backgroundColor: Color(0xfff8f8fa),
body: Column(
children: [
Text('${usermodel.data.length}'), /// number all list user
Text('${searchResult.length}'), /// number search user
// now you have list all user
// and all searched list user
// additional, you need to add logic when query is empty
.................
maybe there error in null-safety, please debug first.
You can simply do this
var myList= []; // declare an empty list
if (response.statusCode == 200) {
var result= UserModel.fromJson(jsonDecode(response.body));
if(result != null){
myList.clear();
myList.addAll(result);
}
}
here is the error message from the console
user.dart
import 'package:cloud_firestore/cloud_firestore.dart';
class User {
final String email;
final String uid;
final String photoUrl;
final String username;
final String bio;
final List<String> followers;
final List<String> following;
const User({
required this.email,
required this.uid,
required this.photoUrl,
required this.username,
required this.bio,
required this.followers,
required this.following,
});
static User fromSnap(DocumentSnapshot snap) {
var snapshot = snap.data() as Map<String, dynamic>;
return User(
username: snapshot["username"],
uid: snapshot["uid"],
email: snapshot["email"],
photoUrl: snapshot["photoUrl"],
bio: snapshot["bio"],
followers: snapshot["followers"],
following: snapshot["following"],
);
}
Map<String, dynamic> toJson() => {
"username": username,
"uid": uid,
"email": email,
"photoUrl": photoUrl,
"bio": bio,
"followers": followers,
"following": following,
};
}
user_provider
import 'package:flutter/material.dart';
import 'package:social_network/models/user.dart';
import 'package:social_network/resources/auth_method.dart';
class UserProvider with ChangeNotifier {
User? _user;
final AuthMethods _authMethods = AuthMethods();
User get getUser => _user!;
Future<void> refreshUser() async {
User? user = await _authMethods.getUserDetails();
_user = user;
notifyListeners();
}
}
add_post_screen
import 'dart:typed_data';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:provider/provider.dart';
import 'package:social_network/providers/user_provider.dart';
import 'package:social_network/resources/firestore_methods.dart';
import 'package:social_network/utils/colors.dart';
import 'package:social_network/utils/utils.dart';
class AddPostScreen extends StatefulWidget {
const AddPostScreen({Key? key}) : super(key: key);
#override
_AddPostScreenState createState() => _AddPostScreenState();
}
class _AddPostScreenState extends State<AddPostScreen> {
Uint8List? _file;
bool _isLoading = false;
final TextEditingController _descriptionController = TextEditingController();
_selectImage(BuildContext parentContext) async {
return showDialog(
context: parentContext,
builder: (BuildContext context) {
return SimpleDialog(
title: const Text('Create a post'),
children: <Widget>[
SimpleDialogOption(
padding: const EdgeInsets.all(20),
child: const Text('Take a photo'),
onPressed: () async {
Navigator.of(context).pop();
Uint8List file = await pickImage(ImageSource.camera);
setState(() {
_file = file;
});
},
),
SimpleDialogOption(
padding: const EdgeInsets.all(20),
child: const Text('Choose from gallery'),
onPressed: () async {
Navigator.of(context).pop();
Uint8List file = await pickImage(ImageSource.gallery);
setState(() {
_file = file;
});
},
),
SimpleDialogOption(
padding: const EdgeInsets.all(20),
child: const Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
});
}
void postImage(
String uid,
String username,
String profileImage,
) async {
setState(() {
_isLoading = true;
});
try {
String res = await FirestoreMethods().uploadPost(
_descriptionController.text, _file!, uid, username, profileImage);
if (res == "Succes") {
setState(() {
_isLoading = false;
});
showSnackBar('Posted!', context);
clearImage();
} else {
showSnackBar(res, context);
}
} catch (e) {
setState(() {
_isLoading = false;
});
showSnackBar(e.toString(), context);
}
}
void clearImage() {
setState(() {
_file = null;
});
}
#override
void dispose() {
super.dispose();
_descriptionController.dispose();
}
#override
Widget build(BuildContext context) {
final UserProvider userProvider = Provider.of<UserProvider>(context);
return _file == null
? Center(
child: IconButton(
icon: const Icon(Icons.upload),
onPressed: () => _selectImage(context),
),
)
: Scaffold(
appBar: AppBar(
backgroundColor: mobileBackgroundColor,
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: clearImage,
),
title: const Text('Post to'),
centerTitle: false,
actions: <Widget>[
TextButton(
onPressed: () => postImage(
userProvider.getUser.uid,
userProvider.getUser.username,
userProvider.getUser.photoUrl,
),
child: const Text(
'Post',
style: TextStyle(
color: Colors.redAccent,
fontWeight: FontWeight.bold,
fontSize: 18,
),
),
),
],
),
body: Column(
children: [
_isLoading
? const LinearProgressIndicator()
: const Padding(
padding: EdgeInsets.only(top: 0),
),
const Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CircleAvatar(
backgroundImage: NetworkImage(
'https://images.unsplash.com/photo-1522441815192-d9f04eb0615c?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=654&q=80',
// userProvider.getUser.photoUrl,
),
),
SizedBox(
width: MediaQuery.of(context).size.width * 0.4,
child: TextField(
controller: _descriptionController,
decoration: const InputDecoration(
hintText: 'Write a caption...',
border: InputBorder.none,
),
maxLines: 8,
),
),
SizedBox(
height: 45,
width: 45,
child: AspectRatio(
aspectRatio: 487 / 451,
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: MemoryImage(_file!),
fit: BoxFit.fill,
alignment: FractionalOffset.topCenter,
),
),
),
),
),
const Divider(),
],
)
],
));
}
}
auth_methods.dart
import 'dart:typed_data';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:social_network/models/user.dart' as model;
import 'package:social_network/resources/storage_methods.dart';
class AuthMethods {
final FirebaseAuth _auth = FirebaseAuth.instance;
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
Future<model.User?> getUserDetails() async {
User currentUser = _auth.currentUser!;
DocumentSnapshot documentSnapshot =
await _firestore.collection('user').doc(currentUser.uid).get();
return model.User.fromSnap(documentSnapshot);
}
//sign up the user
Future<String> signUpUser({
required String email,
required String password,
required String username,
required String bio,
required Uint8List? file,
}) async {
String res = "Some error occurred";
try {
if (email.isNotEmpty ||
password.isNotEmpty ||
username.isNotEmpty ||
bio.isNotEmpty ||
file != null) {
//register the user
UserCredential cred = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
String photoUrl = await StorageMethods()
.uploadImageToStorage('profilePictures', file!, false);
//adding user to our database
model.User _user = model.User(
bio: bio,
username: username,
uid: cred.user!.uid,
email: email,
photoUrl: photoUrl,
following: [],
followers: [],
);
await _firestore.collection("users").doc(cred.user!.uid).set(
_user.toJson(),
);
res = "Succes";
} else {
res = "Please enter all the fields";
}
} catch (err) {
res = err.toString();
}
return res;
}
// logging the user
Future<String> loginUser(
{required String email, required String password}) async {
String res = "Some error occured";
try {
if (email.isNotEmpty || password.isNotEmpty) {
await _auth.signInWithEmailAndPassword(
email: email, password: password);
res = "Succes";
} else {
res = "Please enter all the fields required";
}
} catch (err) {
res = err.toString();
}
return res;
}
}
Hello. I'll try to make a post button and when I try to upload a photo and press the post button I receive this error.
Do you have any solution for this error? Thanks a lot!
Error message:
Restarted application in 474ms.
[VERBOSE-2:ui_dart_state.cc(198)] Unhandled Exception: type 'Null' is not a subtype of type 'Map<String, dynamic>' in type cast
════════ Exception caught by gesture ═══════════════════════════════════════════
Null check operator used on a null value
════════════════════════════════════════════════════════════════════════════════
[VERBOSE-2:profiler_metrics_ios.mm(203)] Error retrieving thread information: (os/kern) object terminated
I believe that your issue in
onPressed: () => postImage(
userProvider.getUser.uid,
userProvider.getUser.username,
userProvider.getUser.photoUrl,
),
Make sure that the user is not null before calling the method,
It would be more helpful to post more code _authMethods.getUserDetails(); what’s inside this method?
UPDATE:
Future<model.User?> getUserDetails() async {
User currentUser = _auth.currentUser!;
DocumentSnapshot documentSnapshot =
await _firestore.collection('user').doc(currentUser.uid).get();
//add the following lines
print('documentSnapshot: $documentSnapshot');
if(documentSnapshot == null) return null;
return model.User.fromSnap(documentSnapshot);
}
my console shows no error but still i cant generate a data base with my app i dont know where's the problem at first when i run the app and add a transaction and then i enter the transaction page it shows 'no transactions' and then when i left the app and get back it shows 'loading' and when i try add another transaction the button add doesnt respond i have to say that when i delete the part of the code about db the app works perfectly but without a database
import 'dart:io';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
import 'transaction.dart';
class TransactionsDatabase {
static final TransactionsDatabase instance = TransactionsDatabase._init();
static Database? _database;
TransactionsDatabase._init();
Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDB();
return _database!;
}
Future<Database> _initDB() async {
Directory documentsDirectory = await getApplicationSupportDirectory();
String path = join(documentsDirectory.path, 'TransactionsDatabase.db');
return await openDatabase(path, version: 1, onCreate: _createDB);
}
Future _createDB(Database db, int version) async {
final idType = 'INTEGER PRIMARY KEY AUTOINCREMENT';
final textType = 'TEXT NOT NULL';
final boolType = 'BOOLEAN NOT NULL';
final doubleType = 'DOUBLE NOT NULL';
await db.execute('''
CREATE TABLE $tableTransactions (
${TransactionFields.id} $idType,
${TransactionFields.isIncome} $boolType,
${TransactionFields.Tname} $textType,
${TransactionFields.Tamount} $doubleType,
${TransactionFields.time} $textType
)
''');
}
Future<int> create(Transactionn transactionn) async {
Database db = await instance.database;
return await db.insert(tableTransactions, transactionn.toJson());
}
Future<List<Transactionn>> readAllNotes() async {
Database db = await instance.database;
var transactions =
await db.query(tableTransactions, orderBy: TransactionFields.Tname);
List<Transactionn> transactionList = transactions.isNotEmpty
? transactions.map((json) => Transactionn.fromJson(json)).toList()
: [];
return transactionList;
}
Future close() async {
final db = await instance.database;
db.close();
}
}
my class exemple look like this : Transaction.dart
final String tableTransactions = 'transactions';
class TransactionFields {
static final List<String> values = [
/// Add all fields
id, isIncome, Tname, Tamount, time
];
static final String id = '_id';
static final String isIncome = 'isIncome';
static final String Tname = 'tname';
static final String Tamount = 'tamount';
static final String time = 'time';
}
class Transactionn {
final int? id;
final bool isIncome;
final String Tname;
final double Tamount;
final DateTime createdTime;
const Transactionn(
{this.id,
required this.isIncome,
required this.Tname,
required this.Tamount,
required this.createdTime});
Map<String, Object?> toJson() => {
TransactionFields.id: id,
TransactionFields.isIncome: isIncome ? 1 : 0,
TransactionFields.Tname: Tname,
TransactionFields.Tamount: Tamount,
TransactionFields.time: createdTime.toIso8601String(),
};
Transactionn copy({
int? id,
bool? isIncome,
String? Tname,
double? Tamount,
DateTime? createdTime,
}) =>
Transactionn(
id: id ?? this.id,
isIncome: isIncome ?? this.isIncome,
Tname: Tname ?? this.Tname,
Tamount: Tamount ?? this.Tamount,
createdTime: createdTime ?? this.createdTime,
);
static Transactionn fromJson(Map<String, Object?> json) => Transactionn(
id: json[TransactionFields.id] as int?,
isIncome: json[TransactionFields.isIncome] == 1,
Tname: json[TransactionFields.Tname] as String,
Tamount: json[TransactionFields.Tamount] as double,
createdTime: DateTime.parse(json[TransactionFields.time] as String),
);
}
in my Homepage class i use a dialogbox to add a transaction to my db :
onPressed: () async {
if (_IncomeName.text.isNotEmpty &
_IncomeAmountName.text.isNotEmpty) {
IncomeName = _IncomeName.text;
IncomeAmountName = _IncomeAmountName.text;
IncomeAmount = double.parse(IncomeAmountName);
IncomeAmount = IncomeAmount.toDouble();
await TransactionsDatabase.instance.create(Transactionn(
isIncome: true,
Tname: IncomeName,
Tamount: IncomeAmount,
createdTime: DateTime.now()));
tt = preferences.getDouble('total');
if (tt == null) {
ttt = IncomeAmount;
} else {
ttt = IncomeAmount + tt!;
}
preferences.setDouble('total', ttt);
setState(() {
capital = preferences.getDouble('total') as double;
});
_IncomeName.clear();
_IncomeAmountName.clear();
Navigator.pop(context);
} else {}
},
and then i have a transactions page where im supposed to see all my db contents transactions.dart
import 'package:flutter/material.dart';
import 'package:mywallet/Database_Helper.dart';
import 'package:mywallet/transaction.dart';
class TransactionsPage extends StatefulWidget {
const TransactionsPage({Key? key}) : super(key: key);
#override
State<TransactionsPage> createState() => _TransactionsPageState();
}
class _TransactionsPageState extends State<TransactionsPage> {
List<Transactionn> transactions = [];
bool isLoading = false;
#override
void initState() {
refreshTransactions();
super.initState();
}
#override
void dispose() {
TransactionsDatabase.instance.close();
super.dispose();
}
Future refreshTransactions() async {
setState(() {
isLoading = true;
});
this.transactions = await TransactionsDatabase.instance.readAllNotes();
setState(() {
isLoading = false;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black26,
body: Container(
padding:
const EdgeInsets.only(top: 40, left: 15, right: 15, bottom: 40),
child: Column(
children: [
Row(
children: [
const SizedBox(
width: 20,
),
IconButton(
icon: Image.asset(
'images/Images/back.png',
width: 24,
height: 24,
),
onPressed: () {
Navigator.pop(context);
},
)
],
),
const SizedBox(
height: 70,
),
Container(
width: MediaQuery.of(context).size.width,
height: 350,
decoration: BoxDecoration(
color: const Color.fromARGB(255, 25, 28, 31),
borderRadius: BorderRadius.circular(30)),
child: Container(
padding: const EdgeInsets.only(
top: 30, left: 20, right: 10, bottom: 10),
child: Column(
children: [
Row(
children: const [
Text('Transactions : ',
style: TextStyle(
fontSize: 14,
color: Color.fromARGB(249, 95, 190, 188),
fontWeight: FontWeight.bold))
],
),
const SizedBox(height: 20),
Center(
child: FutureBuilder<List<Transactionn>>(
future: TransactionsDatabase.instance.readAllNotes(),
builder: (BuildContext context,
AsyncSnapshot<List<Transactionn>> snapshot) {
if (!snapshot.hasData) {
return Center(
child: Text(
'Loading..',
style: TextStyle(
color: Colors.white, fontSize: 20),
));
}
return snapshot.data!.isEmpty
? const Center(
child: Text(
'no traansactiions',
style: TextStyle(
color: Colors.white, fontSize: 20),
))
: ListView(
children:
snapshot.data!.map((Transactionn) {
return Center(
child: ListTile(
title: Text(Transactionn.Tname),
),
);
}).toList(),
);
},
),
)
],
),
))
],
),
),
);
}
}
I am trying to make http post request with 2 var as my parameter. If I type the first and second var (into my textfield) and then I click Submit, it will do http request. It works, but I'm trying to re-format/parse the response into List.
Future<Repair> getRepair(String Id, String title) async {
final String apiUrl =
"*****";
final response =
await http.post(apiUrl, body: {"id": Id, "title": title});
if (response.statusCode == 200) {
final String responseString = response.body;
return repairModelFromJson(responseString);
} else {
print(null);
return null;
}
}
class _MainFetchDataState extends State<MainFetchData> {
Repair _repair;
final TextEditingController caseController = TextEditingController();
final TextEditingController serialController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Fecth"),
),
bottomNavigationBar: Padding(
padding: const EdgeInsets.all(8.0),
child: RaisedButton(
child: Text("Submit"),
onPressed: () async {
final String Id = idController.text;
final String title = titleController.text;
final Repair repair = await getRepair(Id, title);
setState(() {
_repair = repair;
});
},
),
),
body: Column(
children: <Widget>[
TextField(
controller: idController,
),
TextField(
controller: titleController,
),
SizedBox(
height: 32,
),
_repair == null
? Container()
: Text(_repair.movement.toString() != null ? "${_repair.movement.toString()}" : 'Vuoto'),
],
),
);
}
}
and
import 'dart:convert';
Repair repairModelFromJson(String str) => Repair.fromJson(json.decode(str));
String repairModelToJson(Repair data) => json.encode(data.toJson());
class Repair {
String Id;
String title;
String movement;
Repair({
this.Id,
this.title,
this.movement,
});
factory Repair.fromJson(Map<String, dynamic> json) => Repair(
Id: json["id"],
title: json["title"],
movement: json['movement'].toString(),
);
Map<String, dynamic> toJson() => {
"id": Id,
"title": title,
"movement": movement,
};
}
Now, I show this (image) and i would like to show the response like a List.
image