flutter - how to use barcode scanner in flutter - android

I am building a POS system for desktop in flutter. I have used this package -> package to get product suggestions and barcode suggestions. It works fine when I search product by manuallay typing. and when I type manually barcode it also works fine. but when I scan the barcode using the barcode scanner it does not add the product in the list.
How can I detect the event in that form field or add product into list using barcode scanner ?
CODE
Expanded(
child: TypeAheadField(
textFieldConfiguration:
TextFieldConfiguration(
decoration: const InputDecoration(
label:
Text("Search Product"),
prefixIcon: Icon(
Icons.shopping_bag),
border:
OutlineInputBorder()),
controller: _productController),
suggestionsCallback: (pattern) async {
return await POSServices
.getProudctByNameOrBarcode(
pattern);
},
minCharsForSuggestions: 1,
itemBuilder: (context, suggestion) {
suggestion as Map;
return ListTile(
leading: const Icon(
Icons.shopping_bag_outlined,
color: Colors.blue,
),
title: Text(
suggestion['english_name']),
subtitle: Text(
"Rs. ${suggestion['sale_price']}"),
);
},
onSuggestionSelected: (suggestion) {
productData = suggestion as Map;
_productController.text =suggestion['english_name'].toString();
posBuilderController.getProductDetailsWithMultiplePrices(
suggestion['product_id'].toString()).then((data) {
//code
});
},
),
),

Related

Is there a way to use the same globalkey in multiple widgets?? in flutter

So I'm relatively new to flutter and I've been trying to dynamically add Sections(TextFormFields) that are represented in a form that has Form.Helper as its child and in the process to get the saveAndValidate method to work i had to use a GlobalKey to be able to access the currentState of its so i can validate and save user input and such, but whenever i try add another Section to the screen it display this error massage
════════ Exception caught by widgets library ═══════════════════════════════════
Multiple widgets used the same GlobalKey.
════════════════════════════════════════════════════════════════════════════════
here is the code I wrote and I'd appreciate any help in solving this error please.
#1- the code for the model I used:
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
class AddCourse with ChangeNotifier {
String? sectionName;
List<String>? sections;
List<dynamic>? addVids;
AddCourse({this.sectionName, this.sections, this.addVids});
/*where we save our values later to push them to firbase/database*/
Map<String, dynamic> toJson() {
final Map<String, dynamic> sectionData = <String, dynamic>{};
sectionData['Section #'] =
sections; // where current section number is saved and is stored dynamicly and updates as user adds more or less sections.
sectionData['Section Name'] =
sectionName; // where the input of the textformfield is saved and to be later pushed to the database and also is stored in a list so it can hold multiple section names as such.
return sectionData;
}
/* this is another model data for a functionality thats not implemented yet*/
Map<dynamic, dynamic> toJson2() {
final Map<dynamic, dynamic> vidData = <dynamic, dynamic>{};
vidData['Videos #'] = addVids;
return vidData;
}
}
#2 this the code for the form I created
import 'package:flutter/material.dart';
import 'package:snippet_coder_utils/FormHelper.dart';
import '../provider/course_add_model.dart';
class CourseCardBody extends StatefulWidget {
const CourseCardBody({
Key? key,
}) : super(key: key);
#override
State<CourseCardBody> createState() => _CourseCardBodyState();
}
class _CourseCardBodyState extends State<CourseCardBody> {
/* this is where i set up my global key that has the type of GlobalKey<FormState>*/
/*State associated with a [Form] widget. such as textformfields/forms/textfields..etc// the use of the (FormState) is to be able to Access the Functions "save"/"validate"/"reset" as to use them with forms/textformfields that you want to validate thier input or save it*/
GlobalKey<FormState> globalkey = GlobalKey();
AddCourse coursesModel = AddCourse();
#override
void initState() {
super.initState();
coursesModel.sections = List<String>.empty(growable: true);
coursesModel.sections?.add("");
// adds empty sections to the list of sections when the add button is used
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Add Courses'),
centerTitle: true,
),
body: ListView.separated(
shrinkWrap: true,
physics: const ScrollPhysics(),
itemBuilder: ((context, index) => Column(
children: [
_uiWidget(index),
Center(
// the submit button here needs some work to only be show once but for now sorry for this annoying button.
child: FormHelper.submitButton('Save', () {
if (validateAndSave()) {
print(coursesModel.toJson());
}
}),
),
],
)),
separatorBuilder: ((context, index) => const Divider()),
itemCount: coursesModel.sections!.length,
),
);
}
Widget _uiWidget(index) {
/* this form here is the parent of form fields/Formhelper widgets as seen below*/
return Form(
/* -- note here--
if we use a UniqueKey()
instead of our globalkey
here and comment the ValidateAndSave() function here
the form will work in terms of adding and removing sections
but we won't be able to either
save content/input of the user in the fields or
either validate
them so that sucks. */
/*this form is where global key is first used*/
key: globalkey,
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_sectionsContainer(index),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Flexible(
flex: 1,
fit: FlexFit.loose,
child: FormHelper.inputFieldWidgetWithLabel(
context,
'Add Section$index',
'',
'Section Title',
(onValidate) {
if (onValidate.isEmpty) {
return 'section ${index + 1} name cant be empty';
}
return null;
},
(onSavedVal) {
coursesModel.sections![index++] = index.toString();
onSavedVal = index;
},
onChange: (onChangedval) {
coursesModel.sectionName = onChangedval;
},
initialValue: coursesModel.sectionName ?? "",
borderColor: Colors.black,
borderFocusColor: Colors.black,
fontSize: 14,
labelFontSize: 14,
validationColor: Colors.redAccent,
),
),
Visibility(
visible: index == coursesModel.sections!.length - 1,
child: IconButton(
onPressed: () {
addEmailControl();
},
icon: const Icon(
Icons.add_circle,
color: Colors.greenAccent,
),
),
),
Visibility(
visible: index > 0,
child: SizedBox(
width: 35,
child: IconButton(
onPressed: () {
removeEmailControl(index);
},
icon: const Icon(
Icons.remove_circle,
color: Colors.redAccent,
),
),
),
),
],
),
],
),
),
);
}
Widget _sectionsContainer(index) {
/* the widget used to create the current section displayed on the top left of each textformfields*/
return Column(
children: [
Padding(
padding: const EdgeInsets.all(10),
child: Text(
'Section ${index + 1}',
textAlign: TextAlign.left,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
),
],
);
}
void addEmailControl() {
setState(() {
coursesModel.sections!.add('');
});
}
void removeEmailControl(index) {
setState(() {
if (coursesModel.sections!.length > 1) {
coursesModel.sections!.removeAt(index);
}
});
}
bool validateAndSave() {
/* we're especially using the <FormState> that is provided by the Globalkey to be able access the currentState of widget/form that has the global key in order to either validate or save the textformfields input or both in the same time*/
// validate each form
if (globalkey.currentState!.validate()) {
// If all data are correct then save data to out variables
// save each form
globalkey.currentState!.save();
return true;
} else {
return false;
}
}
}
I'm trying my best to figure it out on my own as I want to know how to solve this problem properly and where did I go wrong, and any help is very much appreciated thank you!
I suggest to create List<GlobalKey> variable. When you dynamically add or delete sub forms, you add or remove list items accordingly. It is impossible to use same GlobalKey for multiple widgets. So you need to create separate GlobalKeys for each form.
You may create a file of Global variables that may be shared across multiple files to ensure you are using a single instance.
Example globals.dart file
GlobalKey<SomeState> myGlobalKey = GlobalKey<SomeState>();
Example of implementation inside main.dart (or whatever file)
import './[path-to-globals]/globals.dart' // enter the appropriate path for your project
... // some code
Form(
key: myGlobalKey,
... // code
)
... // maybe more code

Button Text Initialization in flutter with SwitchListTile

I have a SwitchListTile in my App that determine the text that should be written on another button based on its value. Everything is working fine except for one thing which is that the first time you open the app, the initial text on the button will be nothing '' just as it was declared first time until I switch the SwitchListTile for the first time. So I want to know how to make the text appear from the moment you enter this page.
This is my code:
static String buttonText='';
SwitchListTile(
title: const Text('Enable Bluetooth'),
value: _bluetoothState.isEnabled,
onChanged: (bool value) {
// Do the request and update with the true value then
future() async {
// async lambda seems to not working
if (value) {
await FlutterBluetoothSerial.instance.requestEnable();
setState(() {buttonText = "Press to start collection" ; });
} else {
await FlutterBluetoothSerial.instance.requestDisable();
setState(() {buttonText = "Please enable bluetooth in your device" ; });
}
}
future().then((_) {
setState(() {});
});
},
),
.......................
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.red,
padding: const EdgeInsets.symmetric(horizontal: 30, vertical:40),
textStyle:
const TextStyle(fontSize: 30, fontWeight: FontWeight.bold)),
onPressed: () {
if(_bluetoothState.isEnabled){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const BluetoothConnectionTask()),
);
}
},
child: Text(
buttonText,
style: TextStyle(fontSize: 28,color: Colors.black, letterSpacing: 2.0),
),
),
Please update the Text widget set in your elevated button as below.
Text(
_bluetoothState.isEnabled ? "Press to start collection" : "Please enable bluetooth in your device",
style: TextStyle(fontSize: 28,color: Colors.black, letterSpacing: 2.0),
)
And remove
setState(() {buttonText = "Press to start collection" ; });
setState(() {buttonText = "Please enable bluetooth in your device" ; });
from the onChanged method.
It is not working from first time because, onChanged method will get call when you interact with the SwitchListTile.
If still it's not working, Please let me know with the issue.

On a Flutter widget this dart error comes - Expected a value of type 'List<DropdownMenuItem<String>>', but got one of type 'List<dynamic>'

I am very new to flutter. I am trying to create List view with Dynamically generated DropDownButton & And Label .No matter what I do this error occurs and dropdown items not updating.
Expected a value of type 'List<DropdownMenuItem<String>>', but got one of type 'List<dynamic>'
This is my listview builder code
ListView.builder(
itemCount: tasksLength,
itemBuilder: (context, index) {
String roleId = taskRoles[index]['roleId'];
List<DropdownMenuItem<String>> _userList = [DropdownMenuItem<String>(value: '', child: Text('Loading..'))].toList();
if (usersList['roles'] != null && usersList['roles'][roleId] != null) {
_userList = usersList['roles'][roleId]['users'].map((item) {
return DropdownMenuItem<String>(value: item['id'],child: Text(item['name'].toString()));
}).toList();
}
return UserSelect(userList: _userList);
},
),
This is my widget class with the DropDownbutton
class UserSelect extends StatefulWidget {
List<DropdownMenuItem<String>>? userList =
[DropdownMenuItem<String>(value: '', child: Text('Loading..'))].toList();
UserSelect({this.userList});
#override
_UserSelectState createState() => _UserSelectState();
}
class _UserSelectState extends State<UserSelect> {
String _selected_user = '';
String _roleName = 'User Role';
List<DropdownMenuItem<String>> _userList =
[DropdownMenuItem<String>(value: '', child: Text('Loading..'))].toList();
#override
void initState() {
super.initState();
}
#override
void didUpdateWidget(UserSelect oldWidget) {
if (oldWidget.userList != widget.userList) {
_userList = widget.userList!;
}
super.didUpdateWidget(oldWidget);
}
#override
Widget build(BuildContext context) {
return Column(
children: [
Text(
_roleName,
style: TextStyle(
fontFamily: 'Bilo',
fontSize: 16,
color: const Color(0xff3b3e51),
letterSpacing: 0.224,
height: 1.5,
),
textHeightBehavior:
TextHeightBehavior(applyHeightToFirstAscent: false),
textAlign: TextAlign.left,
),
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(18.0),
color: const Color(0xfff6f6f6),
),
child: DropdownButton<String>(
isExpanded: true,
value: (_selected_user.length > 0) ? _selected_user : null,
icon: const Icon(Icons.keyboard_arrow_down),
iconSize: 24,
elevation: 16,
style: const TextStyle(color: Colors.black45),
hint: new Text("Select User"),
underline: Container(
height: 2,
color: Colors.white24,
),
onChanged: (String? newValue) {
setState(() {
_selected_user = newValue!;
});
},
items: _userList),
)
],
);
}
}
Some of codes unnecessary I tried by best to skip this error that is why some junk codes are there.
Please help me to fix this issue or show me right direction.
I think the issue here is the .toList(); method calls here:
List<DropdownMenuItem<String>> _userList =
[DropdownMenuItem<String>(value: '', child: Text('Loading..'))].toList();
toList() in dart returns a list with the type that's supplied to its type parameter. Documentation
When not supplied with a type parameter, I would assume that the toList() method's return type is dynamic.
You can just remove the toList() method call altogether, as you already placed the DropDownMenuItem into a list by placing it between the [square brackets]! Ironically, the type would've been inferred by the list declaration before you overwrote it with toList() and made it dynamic :')
If you DO need to do it this way, you can simply add [items ...].toList<DropdownMenuItem>() which will correctly return a list of type DropdownMenuItem :)

In flutter ListView.builder I got Null value

I created a map called "records", the keys of this map are taken from the user when presed on 'save' botton, and the values are from the time counter that I have in my code.
But the problem is when I create a ListView.builder to export this map indexes to cards, it gave me Null values in each card index !!!
How can I show the real value instead of Null ?!!
Here is my code:
var _item;
List listCount = [];
Map<String, dynamic> records = {};
String name;
createAlertDialog(buildContext, context) {
TextEditingController controller;
return showDialog(
context: context,
// barrierDismissible: false,
builder: (context) {
return AlertDialog(
title: Text(
'Type record name',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18.0),
),
content: TextField(
controller: controller,
onChanged: (value) {
name = value;
}),
actions: [
MaterialButton(
elevation: 5.0,
child: Text('Save'),
onPressed: () {
listCount.add(_item);
print(_item);
records[name] = _item;
print(records);
Navigator.pop(context);
},
),
MaterialButton(
elevation: 5.0,
child: Text('Cancel'),
onPressed: () {
Navigator.pop(context);
},
),
],
);
},
);
}
The variable _item is taking it's value from another site, see this:
StreamBuilder<int>(
stream: _stopWatchTimer2.rawTime,
initialData: 0,
builder: (context, snap) {
final value = snap.data;
final displayTime = StopWatchTimer.getDisplayTime(
value,
hours: _isHours2);
_item = displayTime;
return Padding(
padding: EdgeInsets.all(5.0),
child: Text(displayTime,
style: TextStyle(
fontSize: 30.0, color: Colors.white)),
);
},
),
And here where I create the ListView.builder:
ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: records.length,
itemBuilder: (context, index) {
return MyCard(
colour: Colors.cyanAccent,
maker: Container(
width: 250.0,
height: 75.0,
child: Text(
'${records[index]}',
style: TextStyle(fontSize: 25.0),
textAlign: TextAlign.center,
),
),
);
},
),
The image in the link is a screen shot from my app.
Image
Looking at the _item variable which is initially null. You are not assigning any value to it. Please check your code. You are assigning a null value to your records because _item has not been given any value.
onChanged: (value){
_item = value;
}
you are not giving any value to the _item variable, I'm assuming you wanted to assign the value in the onChanged event like this:
onChanged: (value) {
_item = value;
}
or maybe you wanted to add the name to the list instead?
If I am understanding correctly, you have stored the item values into the records based on name variable in Save button onPressed event. But you are getting the record through the ListView index values. So, there is no record found in the records collection based on that index. So it returns null value.
Provide the index to store the item in the Save button instead of name. Or check the record based on name inside the ListView builder instead of index.

FLUTTER: ERROR TO SEND HTTP POST REQUEST USING A TEXT FIELD AND RAISED BUTTON

I have a FLUTTER problem that I couldn't solve.
Scenario:
1. Implement a QR reader application.
2. The app, read the QR code
3. When you read the QR code, you redirect me to a user's detail page
Problem:
I want to edit that person's data, that's why place a TexFormField, valid fields, but when I call
FUTURE function to send the parameters by post, transforming the body in a JSON so that my server detects it, the button DOES NOTHING.
This is My code
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
child : Text("Escanea el codigo QR ", style: TextStyle(fontSize: 25.0),)
),
),
floatingActionButton: FloatingActionButton(
onPressed: obtenerValorQR,
child: Icon(Icons.settings_overscan,),
backgroundColor:Color(0xFF56AB2F)
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
---------------------------LOGIC -------------------------
Future obtenerValorQR()
async{
_scantemp= await FlutterBarcodeScanner.scanBarcode("#004297", "salir", true);
setState(() {
value=_scantemp;
});
if (value == null) {
Navigator.pushNamed(context, QrPageRoute);
} else {
Navigator.pushNamed(context, HomePageRoute, arguments: value);
}
}
2. App read QR code
Widget _infoPerfilUsuario(BuildContext context , index ){
return Container(
height: 120.0,
child: Card(
child: Padding(
padding: const EdgeInsets.all(15.0),
child: ListTile(
leading: CircleAvatar(backgroundImage:
NetworkImage(widget.usuarios[index].urlFoto), radius: 30.0,),
title: Text("Nombre: ${widget.usuarios[index].nombres}"),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Apellidos: ${widget.usuarios[index].apellidos}"),
Text("Zona: ${widget.usuarios[index].territorio}")
],
),
),
)
),
);
}
QR DETAIL
4. I WANT TO OTHER PARAMETERS IN DETAILPAGE FOR EXAMPLE " PESO" BUT TH RAISED BUTTON DONT COMPILE THE CODE
Code where I send the "peso" parameter that I implement, but does not do what I am looking for.
widget _botonesAcciones(BuildContext context , int index ){
return Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
RaisedButton(child: Text("SAVE "), color: Colors.green,
onPressed: () {
final form = formKey.currentState;
if(form.validate()) {
_sendData( context , index );
Navigator.pushNamed(context, QrPageRoute);
}
}
),
],
);
}
I IMPLEMENT THIS FUNCTION IF THE FIELD IS VALIDATED, I just want the data to be sent, I don't want the response body returned, just send the data to my DataBase
Future <void> _sendData (BuildContext context , int index ) async {
final url = Uri.https( _url,'/searchdata.php');
await http.post(url,
body: json.encode({
"id" : "${widget.usuarios[index].idUsuarioMobile}",
"peso" : peso
}),
);
}
Something is wrong?
I think my mistake is in the sendData () function
Hi the solucion is simple:
void _sendData(BuildContext context , int index ) {
var url = Uri.https( _url,'/updatePuntos.php');
http.post(url,
body: json.encode({
"id" : "${widget.usuarios[index].idUsuarioMobile}",
"peso" : peso
}),
);
Looking for me econtre, the answer to my question, was something as simple as returning a void method and sending the data to the server. You should use,
body: json.encode
it will make your life easier.

Categories

Resources