Getter method returning null value - flutter

I have developed a login page using local db in flutter SQL. I want to display the username in SQL database after the table is created but the getter method is returning null.
I am displaying the username like this in class home
body: Center(
child: user != null ? Text("Saved \n \n Username: '${user.username}' ")
: Text("Not saved"),
),
Here is login page code
BuildContext _ctx;
bool _isLoading = false;
final _formKey = new GlobalKey<FormState>();
final scaffoldKey = new GlobalKey<ScaffoldState>();
String _username,_password;
LoginPagePresenter _presenter;
#override
void initState(){
_presenter = new LoginPagePresenter(this);
}
void _submit(){
final form = _formKey.currentState;
if(form.validate()){
_isLoading = true;
form.save();
_presenter.doLogin(_username, _password);
}
}
void _showsnackbar(String text){
scaffoldKey.currentState.showSnackBar(new SnackBar(
content: new Text(text),
));
}
#override
Widget build(BuildContext context) {
return _isLoading ? Loading() :Scaffold(
appBar: AppBar(
backgroundColor: Colors.black,
title: Text('Login Page',textAlign: TextAlign.center,),
),
body: Container(
padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 50.0),
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
SizedBox(height: 20.0),
TextFormField(
decoration: InputDecoration(labelText:'Username' ),
validator: (val) => val.isEmpty ? 'Enter Username' : null,
onChanged: (val) {
setState(() => _username = val);
},
),
SizedBox(height: 20.0),
TextFormField(
obscureText: true,
decoration: InputDecoration(labelText:'Password' ),
validator: (val) => val.length < 6 ? 'Enter a password 6+ chars long' : null,
onChanged: (val) {
setState(() => _password = val);
},
),
SizedBox(height: 20.0),
RaisedButton(
color: Colors.pink[400],
child: Text(
'Sign In',
style: TextStyle(color: Colors.white),
),
onPressed: () async {
_submit();
}
),
],
),
),
),
);
}
#override
void onLoginError(String error) {
_showsnackbar(error);
setState(() {
_isLoading = false;
});
}
#override
void onLoginSuccess(User user) async {
_showsnackbar(user.toString());
setState(() {
_isLoading = false;
});
var db = new DatabaseHelper();
await db.saveUser(user);
Navigator.of(_ctx).push(MaterialPageRoute<Null>(
builder: (BuildContext context){
return new Home(
user:user,
);
}
));
}
Here is user class
class User{
String _username;
String _password;
User(this._username,this._password);
User.map(dynamic obj){
this._username = obj['username'];
this._password = obj['password'];
}
String get username => _username;
String get password => _password;
Map<String,dynamic> toMap(){
var map = new Map<String,dynamic>();
map["username"] = _username;
map["password"] = _password;
return map;
}
}
And this is database helper class
class DatabaseHelper{
static final DatabaseHelper _instance = new DatabaseHelper.internal();
DatabaseHelper.internal();
factory DatabaseHelper() => _instance;
static Database _db;
Future<Database> get db async{
if(_db!= null)
{
return _db;
}
_db = await initdb();
return _db;
}
initdb() async{
Directory documentDirectory = await getApplicationDocumentsDirectory();
String path = join(documentDirectory.path,"main.db");
var ourDb = await openDatabase(path,version:1,onCreate:_onCreate);
return ourDb;
}
void _onCreate(Database db,int version)async {
await db.execute("CREATE TABLE User(id INTEGER PRIMARY KEY,username TEXT,password TEXT)");
print("Table created");
}
//insertion of data
Future<int> saveUser(User user)async {
var dbClient = await db;
int res = await dbClient.insert("User", user.toMap());
return res;
}
// deleting data
Future<int> deleteUser(User user)async {
var dbClient = await db;
int res = await dbClient.delete("User");
return res;
}
}
this is login presenter
abstract class LoginPageContract{
void onLoginSuccess(User user);
void onLoginError(String error);
}
class LoginPagePresenter{
LoginPageContract _view;
RestData api = new RestData();
LoginPagePresenter(this._view);
doLogin(String username,String password){
api
.login(username, password)
.then((user)=> _view.onLoginSuccess(user))
.catchError((onError)=>_view.onLoginError(onError()));
}
}
This is github link to the code for reference: https://github.com/meadows12/sql
Please help !!

All you have to do is to access the user obejct as "widget.user" instead of "user". So, the following would do the trick :
body: Center(
child: widget.user != null ? Text("Saved \n \n Username: '${widget.user.username}' ")
: Text("Not saved"),
)
There's one more problem in the code. You are not assigning the buildcontext to variable _ctx. So, the screen change didn't happen on your code on the github. I added one line in login.dart as below to make it work :
Widget build(BuildContext context) {
_ctx = context;
return _isLoading ? Loading() :Scaffold(______________
Result :

Related

Singin request with firebase is not working

I'm having a problem trying to do a login validation with firebase. Coincidentally I can create a new firebase account register it and I can enter my application. but when I go back to the home screen, I can't log in with that registered account. What do you think is the mistake I'm making?.
The console returns this to me.
Error image
my screen code
class AuthScreen extends StatefulWidget {
const AuthScreen({Key? key}) : super(key: key);
#override
State<AuthScreen> createState() => _AuthScreenState();
}
class _AuthScreenState extends State<AuthScreen> {
final _auth = FirebaseAuth.instance;
var _isLoading = false;
void _submitAuthForm(
String email,
String userName,
String password,
bool isLogin,
BuildContext ctx,
) async {
UserCredential authResult;
try {
setState(() {
_isLoading = true;
});
if (isLogin) {
authResult = await _auth.signInWithEmailAndPassword(
email: email, password: password);
} else {
authResult = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
await FirebaseFirestore.instance
.collection('users')
.doc(authResult.user!.uid)
.set({
'username': userName,
'email': email,
});
}
} on PlatformException catch (err) {
var message = 'An error ocurred, Please check your credentials';
if (err.message != null) {
message = err.message!;
}
Scaffold.of(ctx).showSnackBar(SnackBar(
content: Text(message),
backgroundColor: Theme.of(ctx).errorColor,
));
setState(() {
_isLoading = false;
});
} catch (err) {
print(err);
setState(() {
_isLoading = false;
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).primaryColor,
body: AuthForm(_submitAuthForm, _isLoading),
);
}
}
authentication code
class AuthForm extends StatefulWidget {
AuthForm(this.submitFn, this.isLoading);
final bool isLoading;
final void Function(String email, String userName, String password,
bool isLogin, BuildContext ctx) submitFn;
#override
State<AuthForm> createState() => _AuthFormState();
}
class _AuthFormState extends State<AuthForm> {
final _formKey = GlobalKey<FormState>();
var _isLogin = true;
var _userEmail = '';
var _userName = '';
var _userPassword = '';
void _trySubmit() {
final isValid = _formKey.currentState!.validate();
FocusScope.of(context).unfocus();
if (isValid) {
_formKey.currentState!.save();
widget.submitFn(
_userEmail.trim(),
_userPassword.trim(),
_userName.trim(),
_isLogin,
context,
);
}
}
#override
Widget build(BuildContext context) {
return Center(
child: Card(
margin: EdgeInsets.all(20),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextFormField(
key: ValueKey('email'),
validator: (value) {
if (value!.isEmpty ||
!value.contains('#') ||
!value.contains('.com')) {
return 'Please enter a valid email';
}
return null;
},
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(labelText: 'Email address'),
onSaved: (value) {
_userEmail = value!;
},
),
if (!_isLogin)
TextFormField(
key: ValueKey('username'),
validator: (value) {
if (value!.isEmpty || value.length < 4) {
return 'Please enter at least 4 characters';
}
return null;
},
decoration: InputDecoration(labelText: 'Username'),
onSaved: (value) {
_userName = value!;
},
),
TextFormField(
key: ValueKey('password'),
validator: (value) {
if (value!.isEmpty || value.length < 7) {
return 'Password must be at least 7 characters long';
}
return null;
},
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
onSaved: (value) {
_userPassword = value!;
},
),
SizedBox(
height: 15,
),
if (widget.isLoading) CircularProgressIndicator(),
if (!widget.isLoading)
ElevatedButton(
onPressed: _trySubmit,
child: Text(_isLogin ? 'Login' : 'Signup'),
),
if (!widget.isLoading)
TextButton(
onPressed: () {
setState(() {
_isLogin = !_isLogin;
});
},
child: Text(_isLogin
? 'Create new account'
: 'I already have a account'))
],
)),
),
),
));
}
}

Multiple showDialog for validation

On my project I need to use several showDialog one after the other.
For user creation, I use a SearchField widget to retrieve info from a table related to the user.
If the SearchField value does not exist I would like to propose the creation. Depending on the choice either the form is in error or I propose to register the user.
For this I use a showDialog in the validator of the SearchField and an if validator is correct.
My problem is that my second dialog box is displayed before validating the first one and even above that of the SearchField.
What is the correct way to do this?
Thank you,
class InformationsPage extends StatefulWidget {
const InformationsPage({
required Key key,
required this.user,
required this.type,
}) : super(key: key);
final User user;
final FenType type;
#override
InformationsPageState createState() => InformationsPageState();
}
class InformationsPageState extends State<InformationsPage>
with AutomaticKeepAliveClientMixin {
InformationsPageState({this.user});
final User? user;
late UserApi _api;
#override
bool get wantKeepAlive => true;
bool _familyIsCreated = false;
late User userSaved;
late FenType type;
//Info Form
var _pseudoController = TextEditingController();
var _familyController = TextEditingController();
#override
void initState() {
super.initState();
_api = UserApi();
_pseudoController = TextEditingController(text: widget.user.pseudo);
_familyController = TextEditingController(text: widget.user.familyName);
userSaved = User.fromUser();
type = widget.type;
}
#override
void dispose() {
_pseudoController.dispose();
_familyController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
super.build(context);
return Column(
children: <Widget>[
FutureBuilder(
future: _api.getFamilies(),
builder: (context, AsyncSnapshot<List<Family>> snapshot) {
if (snapshot.hasError) {
return Center(
child: Text(
"Something wrong with message: ${snapshot.error.toString()}"));
} else if (snapshot.connectionState == ConnectionState.done) {
List<Family> _list = snapshot.data!;
return _buildDropdownSearchFamilies(_list);
} else {
return const Center(child: CircularProgressIndicator());
}
}),
TextFormField(
readOnly: type == FenType.read ? true : false,
inputFormatters: [LowerCaseTextFormatter()],
controller: _pseudoController,
onSaved: (value) => userSaved.pseudo = value,
decoration: const InputDecoration(
icon: Icon(Icons.person),
hintText: 'Pseudo',
labelText: 'Pseudo',
),
validator: (value) =>
value!.isEmpty ? 'Obligatory' : null),
],
);
}
int? _contains(List<Family> list, String? name) {
int? res = -1;
for (Family element in list) {
if (element.name == name) {
res = element.id;
break;
}
}
return res;
}
Widget _buildDropdownSearchFamilies(List<Family> _list) {
return SearchField(
controller: _familyController,
suggestions: _list
.map((e) =>
SearchFieldListItem(e.name!, child: Text(e.name!), item: e.id))
.toList(),
hint: 'Family',
validator: (x) {
if (x!.isEmpty) {
userSaved.familyId = null;
userSaved.familyName = null;
return null;
}
int? id = _contains(_list, x);
if (id == -1) {
userSaved.familyId == null;
showDiaglog(x);
if (userSaved.familyId != null) {
return null;
} else {
return 'Family not exist';
}
} else {
userSaved.familyId = id;
userSaved.familyName = x;
return null;
}
},
searchInputDecoration: const InputDecoration(
labelText: 'Family', icon: Icon(Icons.groups)),
itemHeight: 50,
onTap: (x) {
userSaved.familyId = x.item as int?;
userSaved.familyName = x.child.toString();
});
}
showDiaglog(String family) async {
String title = "Family";
String message =
"Family $family not exist. Create ?";
String textKoButton = "no";
String textOkButton = "yes";
MyDialog alert = MyDialog(
title: title,
message: message,
onPressedKo: koButtonPressed(),
onPressedOk: okButtonPressed(family),
textKoButton: textKoButton,
textOkButton: textOkButton);
await showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
void Function() koButtonPressed() => () {
_familyIsCreated = false;
Navigator.of(context).pop(false);
};
void Function() okButtonPressed(family) => () {
_save(family);
Navigator.of(context).pop();
};
void _save(family) async {
UserApi apiUser = UserApi();
Family oldF = Family.empty();
Family newF = Family.empty();
newF.name = family;
newF.createdAt = oldF.createdAt;
newF.deletedAt = newF.deletedAt;
Map<String, dynamic> data = oldF.toJson(newF);
int res = -1;
res = await apiUser.createFamily(data);
SnackBar snackBar;
if (res != -1) {
snackBar = MyWidget.okSnackBar('Family created');
userSaved.familyId = res;
userSaved.familyName = family;
} else {
snackBar = MyWidget.koSnackBar(
'Family not created');
userSaved.familyId = null;
userSaved.familyName = null;
}
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
}
My form :
class UserFormPage extends StatefulWidget {
static const String routeName = '/admin/user-form';
final User? user;
final FenType fenType;
const UserFormPage({Key? key, required this.user, required this.fenType})
: super(key: key);
#override
_UserFormPageState createState() => _UserFormPageState();
}
class _UserFormPageState extends State<UserFormPage>
with SingleTickerProviderStateMixin {
static final GlobalKey<FormState> _formKey =
GlobalKey<FormState>(debugLabel: '_appState');
static final GlobalKey<InformationsPageState> _infoKey =
GlobalKey<InformationsPageState>();
late TabController _controller;
late User _user;
late User _userSaved;
#override
void initState() {
super.initState();
_controller = TabController(vsync: this, length: 2);
_user = widget.user!;
_userSaved = widget.user!;
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () =>
Navigator.pushReplacementNamed(context, Routes.admUserList),
),
title: const Text('Member'),
actions: <Widget>[
Visibility(
visible: widget.fenType != FenType.read ? true : false,
child: IconButton(
icon: const Icon(Icons.save),
onPressed: () {
if (!_formKey.currentState!.validate()) {
return;
}
showDiaglog();
},
))
],
bottom: TabBar(
controller: _controller,
tabs: const [
Tab(text: 'Info'),
Tab(text: 'Others'),
],
),
),
body: Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Flexible(
child: TabBarView(
controller: _controller,
children: <Widget>[
SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
InformationsPage(
user: _user,
key: _infoKey,
type: widget.fenType),
])),
SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
DetailsPage(
user: _user,
key: _detailsKey,
type: widget.fenType)
],
)),
],
))
],
))),
);
}
void _save() async {
final infoState = _infoKey.currentState;
_userSaved = infoState?.userSaved ?? _user;
_userSaved.pseudo = infoState?.userSaved.pseudo ?? _user.pseudo;
Map<String, dynamic> data = _user.userToJsonClean(_userSaved);
if (!_userSaved.userIsUpdated()) {
final outSnackBar = MyWidget.okSnackBar('Not update');
ScaffoldMessenger.of(context).showSnackBar(outSnackBar);
} else {
UserApi apiUser = UserApi();
bool res = false;
res = widget.fenType == FenType.update
? await apiUser.update(data)
: await apiUser.create(data);
SnackBar snackBar;
res
? snackBar = MyWidget.okSnackBar('Member saved')
: snackBar = MyWidget.koSnackBar(
'Member not saved');
ScaffoldMessenger.of(context).showSnackBar(snackBar);
_user = _userSaved;
if (widget.fenType == FenType.create) {
Navigator.of(context).popAndPushNamed(Routes.admUserList);
}
}
}
void showDiaglog() {
String pseudo = _userSaved.pseudo!;
String title = "Save";
String message = widget.fenType == FenType.create
? "Create member $pseudo ?"
: "Save meber $pseudo ?";
String textKoButton = "no";
String textOkButton = "yes";
MyDialog alert = MyDialog(
title: title,
message: message,
onPressedKo: koButtonPressed(),
onPressedOk: okButtonPressed(),
textKoButton: textKoButton,
textOkButton: textOkButton);
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
void Function() koButtonPressed() => () {
Navigator.of(context).pop(false);
};
void Function() okButtonPressed() => () {
_formKey.currentState!.save();
_save();
Navigator.of(context).pop();
};
}
I resolve this problem to modified the widget SearchField to a DropdownSearch.

RangeError (start): Invalid value: Only valid value is 0: -16 - FLUTTER

I am trying to encrypt a password locally, it is created or changed when the user wishes.
But when I try to change it from the user interface I get this error:
Unhandled Exception: RangeError (start): Invalid value: Only valid value is 0: -16.
although the app still works.
This is the class code:
class SettingsPage extends StatefulWidget {
#override
_State createState() => _State();
static String routeName = '/settings';
static bool switched = false;
static String inputPassword = '0000';
}
class _State extends State<SettingsPage> {
static final key = encrypt.Key.fromLength(32);
static final iv = encrypt.IV.fromLength(1);
static final encrypter = encrypt.Encrypter(encrypt.AES(key));
static encryptAES(text) {
final encrypted = encrypter.encrypt(text, iv: iv);
print(encrypted.bytes);
print(encrypted.base16);
print(encrypted.base64);
return encrypted;
}
static decryptAES(text) {
return encrypter.decrypt(text, iv: iv);
}
TextEditingController tec = TextEditingController();
var encryptedText, plainText;
Future<void> localAuth(BuildContext context) async {
final localAuth = LocalAuthentication();
final didAuthenticate = await localAuth.authenticateWithBiometrics(
localizedReason: 'Please authenticate');
if (didAuthenticate) {
Navigator.pop(context);
}
}
Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
late SharedPreferences prefs;
getSwitchValues() async {
SettingsPage.switched = await getSwitchState();
setState(() {});
}
getPassValues() async{
prefs = await _prefs;
setState(() {
prefs.containsKey('savedPass')? prefs.getString('savedPass'): "";
setState(() {
});
});
}
#override
void initState() {
super.initState();
getSwitchValues();
getPassValues();
}
Future<bool> getSwitchState() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
SettingsPage.switched = prefs.getBool("switched")!;
print(SettingsPage.switched);
return SettingsPage.switched;
}
Future<bool> saveSwitchState(bool value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool("switched", value);
print('Switch Value saved $value');
return prefs.setBool("switched", value);
}
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(paddingSizeLarge),
child:
Column(
children: [
Text('SETTINGS',
style: GoogleFonts.encodeSansSemiCondensed(fontSize: 35.0, fontWeight: FontWeight.w700,color: Palette.secondaryTextColor),
textAlign: TextAlign.center,
),
VerticalSpacing(of: marginSizeDefault),
Container(
child:
ListView(
shrinkWrap: true,
padding: EdgeInsets.all(paddingSizeDefault),
children: [
Row(
children:[
Text('Activate Biometrics : ',
style: GoogleFonts.encodeSansSemiCondensed(fontSize: 20.0, fontWeight: FontWeight.w700,color: Palette.textColor),),
HorizontalSpacing(of: marginSizeXXLarge),
Switch(
value: SettingsPage.switched,
onChanged: (value) {
setState(() {
SettingsPage.switched = value;
saveSwitchState(SettingsPage.switched);
});
screenLock(context: context, correctString: '1234',
canCancel: true,
customizedButtonTap: () async {
await localAuth(context);
},
didOpened: () async {
await localAuth(context);
},);
},
activeTrackColor: Colors.blue,
activeColor: Colors.blue,
),
]),
VerticalSpacing(of: marginSizeLarge),
/* Row(
children:[
Text('Biometrics Settings : ',
style: GoogleFonts.encodeSansSemiCondensed(fontSize: 20.0, fontWeight: FontWeight.w700,color: Palette.textColor),),
HorizontalSpacing(of: marginSizeXXLarge),
IconButton(onPressed: (){ print('bio set');} , icon: const Icon(FeatherIcons.arrowRight, color: Colors.black,))
]),
VerticalSpacing(of: marginSizeLarge),*/
Row(
children:[
Text('Create/Change Password : ',
style: GoogleFonts.encodeSansSemiCondensed(fontSize: 20.0, fontWeight: FontWeight.w700,color: Palette.textColor),),
IconButton( icon: const Icon(FeatherIcons.arrowRight, color: Colors.black,),
onPressed: () async {
final result = await
showOkCancelAlertDialog(
context: context,
title: 'Change or Create a new Password',
message:
'This will remove your existing Password or create a new one',
);
if (result == OkCancelResult.ok) {
final input = (await showTextInputDialog(
textFields: [DialogTextField(keyboardType: TextInputType.numberWithOptions(decimal: true),
),
],
context: context,
title: 'Change or Create a new Password',
message: 'enter your new password',
))!.join();
if (input != null && input.length > 0 && input.length == 4 ) {
context.read<SettingsBloc>().changePassword(input);
SettingsPage.inputPassword = input;
SettingsPage.inputPassword = tec.text;
setState(() {
encryptedText = encryptAES(SettingsPage.inputPassword);
print("PROVA ENCRYPTED TEXT "+encryptedText);
});
prefs.setString('savedPass', encryptedText);
encryptedText = decryptAES(encryptedText);
print("PROVA TESTO DECRIPTATO " + encryptedText);
}
}
},
),
]),
VerticalSpacing(of: 50),
RoundedButton(text:'Log Out',),
],
),
decoration: new BoxDecoration(
color: Palette.primaryLightColor,
borderRadius: BorderRadius.circular(20),
boxShadow: [
BoxShadow(color: Palette.backgroundColor,
),
],
),
),
]
),
);
}
}
both texts are not written to the prompt with the print function. there must be some problem within the conditions and in addition the error I get when changing the password, please if anyone knows how to help me come forward thanks.

Flutter How to populate data from sqflite to dropdown list

I have seen the questions in stackoverflow which are quite similar to my question, but those question and answer dint work for me. So here is my question how to populate data from sqflite to dropdown list. Below are the dart files which I have written.Please help me with the question
dbhelper.dart
import 'package:abc/model/manage_categories.dart';
import 'package:sqflite/sqflite.dart';
import 'dart:async';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
class DatabaseHelper {
static DatabaseHelper _databaseHelper; // Singleton DatabaseHelper
static Database _database; // Singleton Database
String categoriesTable = 'categories_table';
String colId = 'id';
String colTitle = 'title';
String colDate = 'date';
DatabaseHelper._createInstance(); // Named constructor to create instance of DatabaseHelper
factory DatabaseHelper() {
if (_databaseHelper == null) {
_databaseHelper = DatabaseHelper._createInstance(); // This is executed only once, singleton object
}
return _databaseHelper;
}
Future<Database> get database async {
if (_database == null) {
_database = await initializeDatabase();
}
return _database;
}
Future<Database> initializeDatabase() async {
// Get the directory path for both Android and iOS to categories database.
Directory directory = await getApplicationDocumentsDirectory();
String path = directory.path + 'categoriess.db';
// Open/create the database at a given path
var categoriessDatabase = await openDatabase(path, version: 1, onCreate: _createDb);
return categoriessDatabase;
}
void _createDb(Database db, int newVersion) async {
await db.execute('CREATE TABLE $categoriesTable($colId INTEGER PRIMARY KEY AUTOINCREMENT, $colTitle TEXT, '
'$colDate TEXT)');
}
// Fetch Operation: Get all categories objects from database
Future<List<Map<String, dynamic>>> getCategoriesMapList() async {
Database db = await this.database;
// var result = await db.rawQuery('SELECT * FROM $categoriesTable order by $colTitle ASC');
var result = await db.query(categoriesTable, orderBy: '$colTitle ASC');
return result;
}
// Insert Operation: Insert a categories object to database
Future<int> insertCategories(Categories categories) async {
Database db = await this.database;
var result = await db.insert(categoriesTable, categories.toMap());
return result;
}
// Update Operation: Update a categories object and save it to database
Future<int> updateCategories(Categories categories) async {
var db = await this.database;
var result = await db.update(categoriesTable, categories.toMap(), where: '$colId = ?', whereArgs: [categories.id]);
return result;
}
Future<int> updateCategoriesCompleted(Categories categories) async {
var db = await this.database;
var result = await db.update(categoriesTable, categories.toMap(), where: '$colId = ?', whereArgs: [categories.id]);
return result;
}
// Delete Operation: Delete a categories object from database
Future<int> deleteCategories(int id) async {
var db = await this.database;
int result = await db.rawDelete('DELETE FROM $categoriesTable WHERE $colId = $id');
return result;
}
// Get number of categories objects in database
Future<int> getCount() async {
Database db = await this.database;
List<Map<String, dynamic>> x = await db.rawQuery('SELECT COUNT (*) from $categoriesTable');
int result = Sqflite.firstIntValue(x);
return result;
}
// Get the 'Map List' [ List<Map> ] and convert it to 'categories List' [ List<Categories> ]
Future<List<Categories>> getCategoriesList() async {
var categoriesMapList = await getCategoriesMapList(); // Get 'Map List' from database
int count = categoriesMapList.length; // Count the number of map entries in db table
List<Categories> categoriesList = List<Categories>();
// For loop to create a 'categories List' from a 'Map List'
for (int i = 0; i < count; i++) {
categoriesList.add(Categories.fromMapObject(categoriesMapList[i]));
}
return categoriesList;
}
}
Add_store_item.dart
import 'package:flutter/material.dart';
import 'package:abc/database/dbhelper_categories.dart';
import 'package:abc/database/dbhelper_manage_inventory.dart';
import 'package:abc/model/Manageinventory_class.dart';
import 'package:abc/model/manage_categories.dart';
class AddStoreItem extends StatefulWidget {
final Inventory inventory;
AddStoreItem(this.inventory);
#override
State<StatefulWidget> createState() => new AddStoreItemState();
}
class AddStoreItemState extends State<AddStoreItem> {
DatabaseHelper databaseHelper = DatabaseHelper();
List<Categories> categoriesList = <Categories>[];
int count = 0;
DBProvider _db = DBProvider();
TextEditingController _itemController;
TextEditingController _quantityController;
TextEditingController _categoryController;
TextEditingController _unitController;
TextEditingController _locationController;
#override
void initState() {
super.initState();
_loadCategorieslist();
_itemController = new TextEditingController(text: widget.inventory.item);
_quantityController = new TextEditingController(text: widget.inventory.quantity);
_categoryController = new TextEditingController(text: widget.inventory.category);
_unitController = new TextEditingController(text: widget.inventory.unit);
_locationController = new TextEditingController(text: widget.inventory.location);
}
_loadCategorieslist()async{
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Add Inventory')
),
body: SingleChildScrollView(
child: Container(
margin: EdgeInsets.all(15.0),
alignment: Alignment.center,
child: Column(
children: <Widget>[
SizedBox(height: 10),
TextField(
controller: _itemController,
decoration: InputDecoration(labelText: 'Item'),
),
SizedBox(height: 10),
TextField(
controller: _quantityController,
decoration: InputDecoration(labelText: 'Quantity'),
),
SizedBox(height: 10),
DropdownButton<String>(
value: categoriesList,
items: categoriesList.map((String){
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}),
isExpanded: true,
onChanged: (value) {
print("value: $value");
},
hint: Text(
"Units",
style: TextStyle(
// color: Colors.black,
),
),
),
DropdownButton<String>(
items: [
DropdownMenuItem<String>(
value: "1",
child: Text(
"First",
),
),
DropdownMenuItem<String>(
value: "2",
child: Text(
"Second",
),
),
],
isExpanded: true,
onChanged: (value) {
print("value: $value");
},
hint: Text(
"Location",
style: TextStyle(
// color: Colors.black,
),
),
),
SizedBox(height: 10),
RaisedButton(
child: (widget.inventory.id != null) ? Text('Update') : Text('Add Inventory'),
onPressed: () {
_addInventory();
},
),
],
),
),
),
);
}
void _addInventory() {
if (widget.inventory.id != null) {
_db
.updateNote(Inventory.withId(
widget.inventory.id,
_itemController.text,
_quantityController.text,
_categoryController.text,
_unitController.text,
_locationController.text,
))
.then((_) => Navigator.pop(context, 'update'));
} else {
_db
.saveNote(Inventory(
_itemController.text,
_quantityController.text,
_categoryController.text,
_unitController.text,
_locationController.text,
))
.then((_) => Navigator.pop(context, 'save'));
}
}
}
This how I managed to populate the list of data from sqflite to drop down
Declared list from sqflite to AddStoreItemState as below
DatabaseHelper databaseHelper = DatabaseHelper();
List<Categories> categoriesList ;
Categories _category;
Now wrap the drop down button as below
Center(
child: DropdownButtonFormField<Categories>(
hint: Text('Categories'),
value: _category,
onChanged: (Categories value){
setState(() {
_category = value;
});
},
items: categoriesList.map((user) => DropdownMenuItem<Categories>(
child: Text(user.cname),
value: user,
)
).toList(),
),
),
In AddStoreItemState change your _loadCategorieslist()async method to:
Future<List<Categories>> _loadCategorieslist() async => databaseHelper.getCategoriesMapList();
And wrap your DropdownButton with a FutureBuilder
This is how I read data from SqfLite to use it in a drop-down or data table, in this case barcode records.
Here is the model, which includes a fromJson() function like below:
class Barcode {
String code;
String itemNo;
Barcode({
this.code,
this.itemNo,
});
Map<String, dynamic> toMap() => {
'code': code,
'itemNo': itemNo,
};
factory Barcode.fromJson(Map<String, dynamic> parsedJson) {
return Barcode(
code: parsedJson['code'],
itemNo: parsedJson['itemNo'],
);
}
}
Here is how I read barcodes (all) from SqfLite:
static Future<List<Barcode>> getAll() async {
final db = await DbUtil.database;
var response = await db.query(tableName);
List<Barcode> list = response.map((c) => Barcode.fromJson(c)).toList();
return list;
}
Here is for reading just one barcode:
static Future<Barcode> get(String barcode) async {
final db = await DbUtil.database;
var response = await db.query(tableName, where: "$pkName = ?", whereArgs: ['$barcode']);
return response.isNotEmpty ? Barcode.fromJson(response.first) : null;
}
Then to call it:
var barcode = await BarcodeDb.get(scanText);
Try this out, it should work for you.

How to implement search delegate with sqflite flutter

I have created an app that stores some notes in sqlite database. I did all CRUD operations and it's working well, but when I'm trying to make search operation inside my database with SearchDelegate, I got some problem. I'll show you my code before I make search with SearchDelegate
databaseHelper:
import 'dart:async';
import 'package:plants/model/plant.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
class DatabaseHelper {
static final DatabaseHelper _instance = new DatabaseHelper.internal();
factory DatabaseHelper() => _instance;
final String tableNote = 'noteTable';
final String columnId = 'id';
final String columnLocation = 'location';
final String columnTitle = 'title';
final String columnDescription = 'description';
static Database _db;
DatabaseHelper.internal();
Future<Database> get db async {
if (_db != null) {
return _db;
}
_db = await initDb();
return _db;
}
initDb() async {
String databasesPath = await getDatabasesPath();
String path = join(databasesPath, 'notes.db');
// await deleteDatabase(path); // just for testing
var db = await openDatabase(path, version: 1, onCreate: _onCreate);
return db;
}
void _onCreate(Database db, int newVersion) async {
await db.execute(
'CREATE TABLE $tableNote($columnId INTEGER PRIMARY KEY,$columnLocation TEXT, $columnTitle TEXT, $columnDescription TEXT)');
}
Future<int> saveNote(Note note) async {
var dbClient = await db;
var result = await dbClient.insert(tableNote, note.toMap());
// var result = await dbClient.rawInsert(
// 'INSERT INTO $tableNote ($columnTitle, $columnDescription) VALUES (\'${note.title}\', \'${note.description}\')');
return result;
}
Future<List> getAllNotes() async {
var dbClient = await db;
var result = await dbClient.query(tableNote, columns: [columnId, columnLocation , columnTitle, columnDescription]);
// var result = await dbClient.rawQuery('SELECT * FROM $tableNote');
return result.toList();
}
Future<int> getCount() async {
var dbClient = await db;
return Sqflite.firstIntValue(await dbClient.rawQuery('SELECT COUNT(*) FROM $tableNote'));
}
Future<Note> getNote(int id) async {
var dbClient = await db;
List<Map> result = await dbClient.query(tableNote,
columns: [columnId, columnLocation , columnTitle, columnDescription],
where: '$columnId = ?',
whereArgs: [id]);
// var result = await dbClient.rawQuery('SELECT * FROM $tableNote WHERE $columnId = $id');
if (result.length > 0) {
return new Note.fromMap(result.first);
}
return null;
}
Future<int> deleteNote(int id) async {
var dbClient = await db;
return await dbClient.delete(tableNote, where: '$columnId = ?', whereArgs: [id]);
// return await dbClient.rawDelete('DELETE FROM $tableNote WHERE $columnId = $id');
}
Future<int> updateNote(Note note) async {
var dbClient = await db;
return await dbClient.update(tableNote, note.toMap(), where: "$columnId = ?", whereArgs: [note.id]);
// return await dbClient.rawUpdate(
// 'UPDATE $tableNote SET $columnTitle = \'${note.title}\', $columnDescription = \'${note.description}\' WHERE $columnId = ${note.id}');
}
Future close() async {
var dbClient = await db;
return dbClient.close();
}
}
Class Notes
class Note {
int _id;
String _location;
String _title;
String _description;
Note(this._location,this._title, this._description);
Note.map(dynamic obj) {
this._id = obj['id'];
this._location = obj['location'];
this._title = obj['title'];
this._description = obj['description'];
}
int get id => _id;
String get location => _location;
String get title => _title;
String get description => _description;
Map<String, dynamic> toMap() {
var map = new Map<String, dynamic>();
if (_id != null) {
map['id'] = _id;
}
map['location'] = _location;
map['title'] = _title;
map['description'] = _description;
return map;
}
Note.fromMap(Map<String, dynamic> map) {
this._id = map['id'];
this._location = map ['location'];
this._title = map['title'];
this._description = map['description'];
}
}
List.dart
import 'package:flutter/material.dart';
import 'package:plants/AddPlant.dart';
import 'package:plants/model/plant.dart';
import 'database/dbhelper.dart';
class ListViewNote extends StatefulWidget {
#override
State<StatefulWidget> createState() => new ListViewNoteState();
}
class ListViewNoteState extends State<ListViewNote> {
List<Note> items = new List();
DatabaseHelper db = new DatabaseHelper();
#override
void initState() {
super.initState();
db.getAllNotes().then((notes) {
setState(() {
notes.forEach((note) {
items.add(Note.fromMap(note));
});
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Plant List',
),
centerTitle: true,
actions: <Widget>[
IconButton(icon: Icon(Icons.search,
color: Colors.white,), onPressed: (){
showSearch(context: context,
delegate: DataSearch(this.items));
})
],
),
body: Center(
child: ListView.builder(
itemCount: items.length,
padding: const EdgeInsets.all(15.0),
itemBuilder: (context, position) {
return Dismissible(
background: stackBehindDismiss(),
key: ObjectKey(items[position]),
child: Card(
elevation: 2.0,
margin: new EdgeInsets.symmetric(horizontal: 0.0,vertical: 2.0),
child: Column(
children: <Widget>[
ListTile(
title: Text(
'${items[position].title}',
style: TextStyle(
fontSize: 22.0,
color: Colors.deepOrangeAccent,
),
),
subtitle: Text(
'${items[position].description}' + '' + '${items[position].location}',
style: new TextStyle(
fontSize: 18.0,
fontStyle: FontStyle.italic,
),
),
onTap: () => _navigateToNote(context, items[position]),
),
],
),
),
onDismissed: (dirction){
var item = items.elementAt(position);
_deleteNote(context, items[position], position);
Scaffold.of(context).showSnackBar(SnackBar(
content: Text("Item deleted"),
));
},
);
}
),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.green[700],
child: Icon(Icons.add),
onPressed: () => _createNewNote(context),
),
);
}
void _deleteNote(BuildContext context, Note note, int position) async {
db.deleteNote(note.id).then((notes) {
setState(() {
items.removeAt(position);
});
});
}
void _navigateToNote(BuildContext context, Note note) async {
String result = await Navigator.push(
context,MaterialPageRoute(builder: (context) => NoteScreen(note)),
);
if (result == 'update') {
db.getAllNotes().then((notes) {
setState(() {
items.clear();
notes.forEach((note) {
items.add(Note.fromMap(note));
});
});
});
}
}
void _createNewNote(BuildContext context) async {
String result = await Navigator.push(
context,MaterialPageRoute(builder: (context) => NoteScreen(Note('', '', ''))),
);
if (result == 'save') {
db.getAllNotes().then((notes) {
setState(() {
items.clear();
notes.forEach((note) {
items.add(Note.fromMap(note));
});
});
});
}
}
stackBehindDismiss() {
return Container(
alignment: Alignment.centerRight,
padding: EdgeInsets.only(right: 20.0),
color: Colors.green[700],
child: Icon(
Icons.delete,
color: Colors.white,
),
);
}
}
class DataSearch extends SearchDelegate<Note> {
DatabaseHelper db = new DatabaseHelper();
final List<Note> items = new List();
List<Note> suggestion = new List();
// ListViewNoteState i = ListViewNoteState();
DataSearch(this.suggestion);
#override
ThemeData appBarTheme(BuildContext context) {
assert(context != null);
final ThemeData theme = Theme.of(context);
assert(theme != null);
return theme;
}
#override
List<Widget> buildActions(BuildContext context) {
return [
IconButton(icon: Icon(Icons.clear), onPressed: () {
query = '';
} )
];
}
#override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow,
progress: transitionAnimation,
),
onPressed: (){
close(context, null);
},
);
}
#override
Widget buildResults(BuildContext context) {
}
#override
Widget buildSuggestions(BuildContext context) {
final suggestion = query.isEmpty
? items
: items.where((target) => target.title.startsWith(query)).toList();
if(items.isEmpty)
{
print("Null");
}
return ListView.builder(
itemBuilder: (context, position)=>
ListTile(
title: Text(items[position].title),
),
itemCount: suggestion.length,
);
}
}
On CRUD, everything is working well and I'm adding 3 records but when I'm using SearchDelegate to implement search, I not getting any result.
The thing I need is to searchlist from database using searchbar
Try this:
return ListView.builder(
itemBuilder: (context, index)=>
ListTile(
title: Text(suggestion[index].title),
),
It should work and display the right results, at least mine is working this way, but I think you'll have to point to items list when you build your results or when you tap to open it or something like that.