Related
I bought an online template app and i am trying to hardcode my email and password credentials in my flutter frontend because i don't have access to the backend api yet to change from email/password auth to phone auth, so i want to force code the logic into my flutter widget.
This means i am trying to implement the onPressed: () { controller.login(); }, function on a login button to get me to the home screen with my customized widget.
The original code given to me works fine when i hardcode the credentials in the text form field but when i hardcode the text form field in my customized widget and use same onPressed: () { controller.login(); }, function it don't work.
I want to know if it's because of i'm in a different state management or there's something i'm failing to do.
I will give the original code and my customized UI code in the snippets for comparison.
PS: i even tried to use same text form field in my widget but hide it with Visibility() in flutter. When i use Visibility() in the original code, onPressed: () { controller.login(); }, works but when i use it in my customized widget, it doest.
How do work around this? If you need more clarification, i am willing to offer. Thanks.
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../../../common/helper.dart';
import '../../../../../common/ui.dart';
import '../../../../models/setting_model.dart';
import '../../../../routes/app_routes.dart';
import '../../../../services/settings_service.dart';
import '../../../global_widgets/block_button_widget.dart';
import '../../../global_widgets/circular_loading_widget.dart';
import '../../../global_widgets/text_field_widget.dart';
import '../../controllers/auth_controller.dart';
class LoginView extends GetView<AuthController> {
final Setting _settings = Get.find<SettingsService>().setting.value;
#override
Widget build(BuildContext context) {
controller.loginFormKey = new GlobalKey<FormState>();
return Visibility(
visible: false,
child: WillPopScope(
onWillPop: Helper().onWillPop,
child: Scaffold(
appBar: AppBar(
title: Text(
"Login".tr,
style: Get.textTheme.headline6
.merge(TextStyle(color: context.theme.primaryColor)),
),
centerTitle: true,
backgroundColor: Get.theme.colorScheme.secondary,
automaticallyImplyLeading: false,
elevation: 0,
),
body: Form(
key: controller.loginFormKey,
child: ListView(
primary: true,
children: [
Stack(
alignment: AlignmentDirectional.bottomCenter,
children: [
Container(
height: 180,
width: Get.width,
decoration: BoxDecoration(
color: Get.theme.colorScheme.secondary,
borderRadius:
BorderRadius.vertical(bottom: Radius.circular(10)),
boxShadow: [
BoxShadow(
color: Get.theme.focusColor.withOpacity(0.2),
blurRadius: 10,
offset: Offset(0, 5)),
],
),
margin: EdgeInsets.only(bottom: 50),
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
children: [
Text(
_settings.salonAppName,
style: Get.textTheme.headline6.merge(TextStyle(
color: Get.theme.primaryColor, fontSize: 24)),
),
SizedBox(height: 5),
Text(
"Welcome to the best salon service system!".tr,
style: Get.textTheme.caption.merge(
TextStyle(color: Get.theme.primaryColor)),
textAlign: TextAlign.center,
),
// Text("Fill the following credentials to login your account", style: Get.textTheme.caption.merge(TextStyle(color: Get.theme.primaryColor))),
],
),
),
),
Container(
decoration: Ui.getBoxDecoration(
radius: 14,
border:
Border.all(width: 5, color: Get.theme.primaryColor),
),
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(10)),
child: Image.asset(
'assets/icon/icon.png',
fit: BoxFit.cover,
width: 100,
height: 100,
),
),
),
],
),
Obx(() {
if (controller.loading.isTrue)
return CircularLoadingWidget(height: 300);
else {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Visibility(
visible: false,
maintainState: true,
child: TextFieldWidget(
labelText: "Email Address".tr,
hintText: "johndoe#gmail.com".tr,
initialValue: 'salon#demo.com',
onSaved: (input) =>
controller.currentUser.value.email = input,
validator: (input) => !input.contains('#')
? "Should be a valid email".tr
: null,
iconData: Icons.alternate_email,
),
),
Obx(() {
return Visibility(
visible: false,
maintainState: true,
child: TextFieldWidget(
labelText: "Password".tr,
hintText: "••••••••••••".tr,
initialValue: '123456',
onSaved: (input) =>
controller.currentUser.value.password = input,
validator: (input) => input.length < 3
? "Should be more than 3 characters".tr
: null,
),
);
}),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
TextButton(
onPressed: () {
Get.toNamed(Routes.FORGOT_PASSWORD);
},
child: Text("Forgot Password?".tr),
),
],
).paddingSymmetric(horizontal: 20),
BlockButtonWidget(
onPressed: () {
controller.login();
},
color: Get.theme.colorScheme.secondary,
text: Text(
"Login".tr,
style: Get.textTheme.headline6.merge(
TextStyle(color: Get.theme.primaryColor)),
),
).paddingSymmetric(vertical: 10, horizontal: 20),
TextButton(
onPressed: () {
//Get.toNamed(Routes.REGISTER);
},
child: Text("You don't have an account?".tr),
).paddingOnly(top: 20),
GestureDetector(
onTap: () {
Get.toNamed(Routes.SETTINGS_LANGUAGE);
},
child: Text(
Get.locale.toString().tr,
textAlign: TextAlign.center,
),
),
],
);
}
}),
],
),
),
),
),
);
}
}
THIS IS THE ORIGINAL WIDGET CODE
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../../routes/app_routes.dart';
import '../../../global_widgets/circular_loading_widget.dart';
import '../../../global_widgets/text_field_widget.dart';
import '../../controllers/auth_controller.dart';
import 'login_view.dart';
import 'pin_number.dart';
import 'keyboard_number.dart';
class PinScreen extends StatefulWidget {
const PinScreen({Key key}) : super(key: key);
#override
State<PinScreen> createState() => _PinScreenState();
}
class _PinScreenState extends State<PinScreen> {
List<String> currentPin = ["", "", "", ""];
TextEditingController pinOneController = TextEditingController();
TextEditingController pinTwoController = TextEditingController();
TextEditingController pinThreeController = TextEditingController();
TextEditingController pinFourController = TextEditingController();
var outlineInputBorder = OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide(color: Colors.transparent),
);
int pinIndex = 0;
#override
Widget build(BuildContext context) {
final controller = Get.find<AuthController>();
controller.loginFormKey = new GlobalKey<FormState>();
return Form(
key: controller.loginFormKey,
child: SafeArea(
child: Column(
children: [
buildExitButton(),
Obx(() {
if (controller.loading.isTrue)
return CircularLoadingWidget(height: 300);
else {
return Expanded(
child: Container(
alignment: Alignment(0, 0.5),
padding: EdgeInsets.symmetric(horizontal: 16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
buildSecurityText(),
SizedBox(height: 20.0),
buildPinRow(),
SizedBox(height: 10.0),
buildNumberPad(),
SizedBox(height: 20.0),
Visibility(
visible: false,
maintainState: true,
child: TextFieldWidget(
labelText: "Email Address".tr,
hintText: "johndoe#gmail.com".tr,
initialValue: 'salon#demo.com',
validator: (input) => !input.contains('#')
? "Should be a valid email".tr
: null,
iconData: Icons.alternate_email,
),
),
Obx(() {
return Visibility(
visible: false,
maintainState: true,
child: TextFieldWidget(
labelText: "Password".tr,
hintText: "••••••••••••".tr,
initialValue: '123456',
validator: (input) => input.length < 3
? "Should be more than 3 characters".tr
: null,
iconData: Icons.lock_outline,
keyboardType: TextInputType.visiblePassword,
suffixIcon: IconButton(
onPressed: () {
controller.hidePassword.value =
!controller.hidePassword.value;
},
color: Theme.of(context).focusColor,
icon: Icon(controller.hidePassword.value
? Icons.visibility_outlined
: Icons.visibility_off_outlined),
),
),
);
}),
Container(
child: new RichText(
text: new TextSpan(
children: [
new TextSpan(
recognizer: TapGestureRecognizer()
..onTap = () {
// Get.toNamed(Routes.REGISTER);
},
text: 'Forgot Pin ?',
style: new TextStyle(
color: Color(0xff3498DB),
fontSize: 14,
fontWeight: FontWeight.w500),
),
],
),
),
),
SizedBox(height: 20.0),
MaterialButton(
onPressed: () {
controller.login();
},
color: Color(0xff34495E),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.18),
),
padding: EdgeInsets.symmetric(
horizontal: 30, vertical: 10),
minWidth: double.infinity,
child: Text(
'Next',
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.w600),
),
),
SizedBox(height: 32.0),
],
),
),
);
}
})
],
),
),
);
}
buildNumberPad() {
return Expanded(
child: Container(
alignment: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
KeyboardNumber(
n: 1,
onPressed: () {
pinIndexSetup("1");
},
),
KeyboardNumber(
n: 2,
onPressed: () {
pinIndexSetup("2");
},
),
KeyboardNumber(
n: 3,
onPressed: () {
pinIndexSetup("3");
},
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
KeyboardNumber(
n: 4,
onPressed: () {
pinIndexSetup("4");
},
),
KeyboardNumber(
n: 5,
onPressed: () {
pinIndexSetup("5");
},
),
KeyboardNumber(
n: 6,
onPressed: () {
pinIndexSetup("6");
},
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
KeyboardNumber(
n: 7,
onPressed: () {
pinIndexSetup("7");
},
),
KeyboardNumber(
n: 8,
onPressed: () {
pinIndexSetup("8");
},
),
KeyboardNumber(
n: 9,
onPressed: () {
pinIndexSetup("9");
},
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
width: 60.0,
child: MaterialButton(
onPressed: null,
child: SizedBox(),
),
),
KeyboardNumber(
n: 0,
onPressed: () {
pinIndexSetup("0");
},
),
Container(
width: 60.0,
child: MaterialButton(
onPressed: () {
clearPin();
},
height: 60.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(60.0),
),
child: Image.asset(
'assets/icon/clear-symbol.png',
),
),
)
],
),
],
),
),
),
);
}
clearPin() {
if (pinIndex == 0)
pinIndex = 0;
else if (pinIndex == 4) {
setPin(pinIndex, "");
currentPin[pinIndex - 1] = "";
pinIndex--;
} else {
setPin(pinIndex, "");
currentPin[pinIndex - 1] = "";
pinIndex--;
}
}
pinIndexSetup(String text) {
if (pinIndex == 0)
pinIndex = 1;
else if (pinIndex < 4) pinIndex++;
setPin(pinIndex, text);
currentPin[pinIndex - 1] = text;
String strPin = "";
currentPin.forEach((e) {
strPin += e;
});
if (pinIndex == 4) print(strPin);
}
setPin(int n, String text) {
switch (n) {
case 1:
pinOneController.text = text;
break;
case 2:
pinTwoController.text = text;
break;
case 3:
pinThreeController.text = text;
break;
case 4:
pinFourController.text = text;
break;
}
}
buildExitButton() {
return Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: MaterialButton(
onPressed: () {
Navigator.pop(context);
},
height: 50.0,
minWidth: 50.0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0),
),
child: Icon(
Icons.clear,
color: Colors.black54,
),
),
),
],
);
}
buildSecurityText() {
return Column(
children: [
Align(
alignment: Alignment.topLeft,
child: Text(
'Enter PIN',
style: TextStyle(
color: Color(0xff151515),
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
SizedBox(
height: 12,
),
Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.only(right: 80),
child: Text(
'Enter 4 digit PIN to access your account ',
style: TextStyle(
color: Color(0xff151515),
fontSize: 14,
fontWeight: FontWeight.w500,
fontStyle: FontStyle.normal,
),
),
),
),
],
);
}
buildPinRow() {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
PINNumber(
outlineInputBorder: outlineInputBorder,
textEditingController: pinOneController,
),
PINNumber(
outlineInputBorder: outlineInputBorder,
textEditingController: pinTwoController,
),
PINNumber(
outlineInputBorder: outlineInputBorder,
textEditingController: pinThreeController,
),
PINNumber(
outlineInputBorder: outlineInputBorder,
textEditingController: pinFourController,
),
],
);
}
}
THIS IS MY CUSTOMIZED WIDGET TREE/CODE
when i navigate from NewSales screen to CreateItem screen and add item and press the add button
the item is added to sqflite database then it navigates back to new sales but the state is not updated , it's updated only if i restarted the app
the NewSales screen
class _NewSalesState extends State<NewSales> {
final controller = TextEditingController();
showAlertDialog(BuildContext context,String name) {
// Create button
// Create AlertDialog
AlertDialog alert = AlertDialog(
title: const Text("Alert"),
content: const Text("you want to delete this item?"),
actions: [
TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.green)),
child: const Text("CANCEL", style: TextStyle(color: Colors.white)),
onPressed: () {
Navigator.of(context).pop();
},
),
BlocBuilder<SalesCubit, SalesState>(
builder: (context, state) {
final bloc=BlocProvider.of<SalesCubit>(context);
return TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.red)),
child: const Text(
"DELETE",
style: TextStyle(color: Colors.white),
),
onPressed: () {
Navigator.of(context).pop();
bloc.deleteItem(name).then((value) {
bloc.getAllItems();
});
},
);
},
)
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
// #override
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery
.of(context)
.size;
return BlocConsumer<SalesCubit, SalesState>(
listener: (context, state) {},
builder: (context, state) {
final bloc = BlocProvider.of<SalesCubit>(context);
if (state is SalesInitial) {
bloc.getAllItems();
}
return Scaffold(
drawer: const navDrawer(),
appBar: AppBar(
title: const Text("Ticket"),
actions: [
IconButton(
onPressed: () async {
String barcodeScanRes;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
barcodeScanRes = await FlutterBarcodeScanner.scanBarcode(
'#ff6666', 'Cancel', true, ScanMode.BARCODE);
print('barcodeScanRes $barcodeScanRes');
print(bloc.bsResult);
} on PlatformException {
barcodeScanRes = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
bloc.toggleSearch();
controller.text = barcodeScanRes;
bloc.filterItems(barcodeScanRes);
},
icon: const Icon(Icons.scanner),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: IconButton(
onPressed: () {
Navigator.of(context).pushNamed(Routes.addCustomerRoute);
},
icon: Icon(Icons.person_add)),
),
],
),
body: Column(
children: [
// the first button
Container(
width: double.infinity,
height: deviceSize.height * .1,
color: Colors.grey,
child: GestureDetector(
onTap: ()=>displayMessage("an item was charged successfully", context),
child: Padding(
padding: const EdgeInsets.all(10),
child: Container(
color: Colors.green,
child: const Center(
child: Text("charge",style: TextStyle(color: Colors.white),),
),
),
),
),
),
// the second container
SizedBox(
width: deviceSize.width,
height: deviceSize.height * .1,
child: Row(
children: [
DecoratedBox(
decoration:
BoxDecoration(border: Border.all(color: Colors.grey)),
child: SizedBox(
width: deviceSize.width * .8,
child: bloc.isSearch
? TextFormField(
autofocus: true,
controller: controller,
decoration:
const InputDecoration(hintText: "Search"),
onChanged: (value) {
bloc.filterItems(controller.text);
},
)
: DropdownButtonFormField<String>(
// underline: Container(),
// value: "Discounts",
hint: const Padding(
padding: EdgeInsets.only(left: 10),
child: Text('Please choose type'),
),
items: <String>['Discounts', 'All Items']
.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (_) {},
),
),
),
DecoratedBox(
decoration:
BoxDecoration(border: Border.all(color: Colors.grey)),
child: SizedBox(
width: deviceSize.width * .2,
child: IconButton(
onPressed: () {
bloc.toggleSearch();
if (!bloc.isSearch) {
bloc.filterItems('');
}
},
icon: Icon(
!bloc.isSearch ? Icons.search : Icons.close)),
),
)
],
),
),
// the third container
if (state is IsLoading || state is SalesInitial)
const Center(
child: CircularProgressIndicator(
color: Colors.green,
backgroundColor: Colors.green,
),
),
if (state is Loaded || state is IsSearch || state is SearchDone)
bloc.items.isEmpty
? const Center(
child: Text("no items added yet"),
)
: Expanded(
child: bloc.filteredItems.isEmpty
? const Center(
child: Text(
"no items found with this name",
style: TextStyle(color: Colors.green),
),
)
: ListView.builder(
itemCount: bloc.filteredItems.length,
itemBuilder: (context, i) {
final item = bloc.filteredItems[i];
return Card(
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.green,
radius: 20,
child: Text(item.price),
),
title: Text(item.name),
subtitle: Text(item.barcode),
trailing: Column(
children: [
IconButton(
onPressed: () {
showAlertDialog(context,item.name);
// bloc.deleteItem(item.name).then((value) {
// bloc.getAllItems();
// });
},
icon: const Icon(
Icons.delete,
color: Colors.red,
))
],
)),
);
}))
],
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: ()async {
Navigator.of(context).pushNamed(Routes.createItemRoute);
},
),
);
},
);
}
}
the CreateItem screen
class _CreateItemState extends State<CreateItem> {
final nameController = TextEditingController();
final priceController = TextEditingController();
final costController = TextEditingController();
final skuController = TextEditingController();
final barcodeController = TextEditingController();
final inStockController = TextEditingController();
bool each = true; // bool variable for check box
bool isColor = true;
bool switchValue = false;
File? file;
String base64File = "";
String path = "";
final _formKey = GlobalKey<FormState>();
#override
void dispose() {
nameController.dispose();
priceController.dispose();
costController.dispose();
skuController.dispose();
barcodeController.dispose();
inStockController.dispose();
super.dispose();
}
Future pickImage(ImageSource source) async {
File? image1;
XFile imageFile;
final imagePicker = ImagePicker();
final image = await imagePicker.pickImage(source: source);
imageFile = image!;
image1 = File(imageFile.path);
List<int> fileUnit8 = image1.readAsBytesSync();
setState(() {
base64File = base64.encode(fileUnit8);
});
}
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
return BlocProvider(
create: (BuildContext context) => CreateItemCubit(),
child: Builder(builder: (context){
final bloc=BlocProvider.of<CreateItemCubit>(context);
return Scaffold(
appBar: AppBar(
leading: IconButton(
onPressed: () => Navigator.of(context).pushNamedAndRemoveUntil(Routes.newSalesRoute, (route) => false),
icon: const Icon(Icons.arrow_back)),
title: const Text("Create Item"),
actions: [TextButton(onPressed: () {}, child: const Text("SAVE"))],
),
body: Padding(
padding: const EdgeInsets.all(10),
child: Form(
key: _formKey,
child: ListView(
children: [
TextFormField(
controller: nameController,
cursorColor: ColorManager.black,
decoration: const InputDecoration(hintText: "Name"),
validator: (value) {
if (value!.isEmpty || value.length < 5) {
return "name can't be less than 5 chars";
}
return null;
},
),
gapH24,
Text(
"Category",
style: TextStyle(color: ColorManager.grey),
),
SizedBox(
width: deviceSize.width,
child: DropdownButtonFormField<String>(
// value: "Categories",
hint: const Padding(
padding: EdgeInsets.only(left: 10),
child: Text('No Category'),
),
items: <String>['No Category', 'Create Category']
.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (_) {},
),
),
gapH24,
const Text(
"Sold by",
style: TextStyle(color: Colors.black),
),
gapH24,
Row(
children: [
Checkbox(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(5.0))), // Rounded Checkbox
value: each,
onChanged: (inputValue) {
setState(() {
each = !each;
});
},
),
gapW4,
const Text(
"Each",
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
gapH24,
Row(
children: [
Checkbox(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(5.0))), // Rounded Checkbox
value: !each,
onChanged: (inputValue) {
setState(() {
each = !each;
});
},
),
gapW4,
const Text(
"Weight",
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
TextFormField(
controller: priceController,
decoration: InputDecoration(
hintText: "Price",
hintStyle: TextStyle(color: ColorManager.grey)),
validator: (value) {
if (value!.isEmpty) {
return "price can,t be empty";
}
return null;
},
),
gapH4,
Text(
"leave the field blank to indicate price upon sale",
style: TextStyle(color: ColorManager.grey),
),
gapH20,
Text(
"Cost",
style: TextStyle(color: ColorManager.grey),
),
TextFormField(
controller: costController,
decoration: InputDecoration(
hintText: "cost",
hintStyle: TextStyle(color: ColorManager.black)),
validator: (value) {
if (value!.isEmpty) {
return "cost can't be empty";
}
return null;
},
),
gapH20,
Text(
"SKU",
style: TextStyle(color: ColorManager.grey),
),
TextFormField(
controller: skuController,
decoration: InputDecoration(
hintText: "Sku",
hintStyle: TextStyle(color: ColorManager.black)),
validator: (value) {
if (value!.isEmpty) {
return "Sku can't be empty";
}
return null;
},
),
gapH30,
TextFormField(
controller: barcodeController,
decoration: InputDecoration(
hintText: "Barcode",
hintStyle: TextStyle(color: ColorManager.grey)),
validator: (value) {
if (value!.isEmpty) {
return "Barcode can't be empty";
}
return null;
},
),
gapH30,
// Divider(thickness: 1,color: ColorManager.black,),
Text(
"Inventory",
style: TextStyle(
color: ColorManager.green,
fontSize: 15,
fontWeight: FontWeight.bold),
),
// ListTile(
// title: Text("TrackStock",style: TextStyle(color: ColorManager.green,fontSize: 15,fontWeight: FontWeight.bold)),
// trailing: Switch(value: switchValue, onChanged: (bool value) {
// setState(() {
// switchValue=!switchValue;
// });
// },),
// ),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("TrackStock",
style: TextStyle(
color: ColorManager.grey,
fontSize: 15,
fontWeight: FontWeight.bold)),
Switch(
value: switchValue,
onChanged: (bool value) {
setState(() {
switchValue = !switchValue;
});
},
),
],
),
gapH10,
if (switchValue)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"in stock",
style:
TextStyle(color: ColorManager.grey, fontSize: 15),
),
TextFormField(
keyboardType: TextInputType.number,
controller: inStockController,
decoration: const InputDecoration(hintText: "0"),
validator: (value) {
if (value!.isEmpty) {
return "value can't be empty";
}
return null;
},
)
],
),
gapH20,
Text(
"Representation in POS",
style: TextStyle(
color: ColorManager.green,
fontSize: 15,
fontWeight: FontWeight.bold),
),
gapH15,
Row(
children: [
Checkbox(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(5.0))), // Rounded Checkbox
value: isColor,
onChanged: (inputValue) {
setState(() {
if (!isColor) {
isColor = !isColor;
}
});
},
),
gapW4,
const Text(
"Color and Shape",
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
gapH10,
Row(
children: [
Checkbox(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(5.0))), // Rounded Checkbox
value: !isColor,
onChanged: (inputValue) {
setState(() {
if (isColor) {
isColor = !isColor;
}
});
},
),
gapW4,
const Text(
"Image",
style: TextStyle(fontWeight: FontWeight.bold),
),
],
),
isColor
? GridView.builder(
physics:
const NeverScrollableScrollPhysics(), // to disable GridView's scrolling
shrinkWrap: true, // You won't see infinite size error
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
crossAxisSpacing: 5.0,
mainAxisSpacing: 5.0,
),
itemCount: containers().length,
itemBuilder: (BuildContext context, int index) {
return containers()[index];
},
)
: Padding(
padding: const EdgeInsets.all(10),
child: Row(
children: [
Expanded(
flex: 1,
child: base64File == ""
? const Icon(Icons.person)
: Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(5)),
child: Image.memory(
base64.decode(base64File)))),
gapW4,
Expanded(
flex: 2,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
TextButton(
onPressed: () =>
pickImage(ImageSource.camera),
child: Row(
children: [
Icon(
Icons.camera_alt,
color: ColorManager.black,
),
gapW8,
Text(
"Take a photo",
style: TextStyle(
color: ColorManager.black,
),
)
],
),
),
const Divider(
thickness: 1,
color: Colors.grey,
),
TextButton(
onPressed: () =>
pickImage(ImageSource.gallery),
child: Row(
children: [
Icon(Icons.camera_alt,
color: ColorManager.black),
gapW8,
Text(
"Choose from gallery",
style: TextStyle(
color: ColorManager.black,
),
)
],
),
)
],
),
)
],
),
)
],
),
),
),
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.save,color: Colors.white,),
onPressed: () async {
bool isValid = _formKey.currentState!.validate();
if (isValid) {
FocusScope.of(context).unfocus();
ItemModel? item=await bloc.checkItem(nameController.text);
if(item!=null){
displayMessage("this item was inserted before", context);
}else{
int? res=await bloc.saveItem(ItemModel(
nameController.text,
priceController.text,
costController.text,
skuController.text,
barcodeController.text));
if(res!=null){
displayMessage("an item was inserted successfully", context);
Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (context)=>const NewSales()), (route) => false);
}
}
}
},
),
);
}
),
);
}
}
this is the SaleCubit
class SalesCubit extends Cubit<SalesState> {
SalesCubit() : super(SalesInitial());
bool isSearch=false;
ItemDBHelper db=ItemDBHelper();
List<ItemModel> items=[];
List<ItemModel> filteredItems=[];
String bsResult='Unknown'; //barcode search result
void toggleSearch(){
isSearch=!isSearch;
emit(IsSearch());
}
void setBarcodeResult(String value){
bsResult=value;
emit(SearchDone());
}
void filterItems(String query){
// emit(Searching());
query.isEmpty?
filteredItems=items:
filteredItems=items.where((item) => item.name.toLowerCase().contains(query.toLowerCase())).toList();
emit(SearchDone());
}
Future<List<ItemModel>?> getAllItems()async{
try{
emit(IsLoading());
items=await db.getAllItems();
filteredItems=items;
print(items);
return items;
}finally{
emit(Loaded());
}
}
Future<void> deleteItem(String name)async{
await db.deleteItem(name);
emit(SearchDone());
}
}
this is the SalesState
part of 'sales_cubit.dart';
#immutable
abstract class SalesState {}
class SalesInitial extends SalesState {}
class IsSearch extends SalesState {}
class IsLoading extends SalesState {}
class Loaded extends SalesState {}
class Searching extends SalesState {}
class SearchDone extends SalesState {}
this is my first time using community to ask about my project. First thing first, english isn't my first language and I'm a very beginner in flutter world. I'm trying to build my first mobile application using flutter and now I'm trying to connect my project to firebase (I looked at youtube tutorial). I don't know if the firebase already connect because when I'm trying to run the application and go to registration page, there this error message.
And here is my code:
import 'package:dfu_check_application/common/auth_controller.dart';
import 'package:flutter/material.dart';
import 'package:dfu_check_application/common/theme_helper.dart';
import 'package:dfu_check_application/pages/widgets/header_widget.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:hexcolor/hexcolor.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'profile_page.dart';
class RegistrationPage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _RegistrationPageState();
}
}
class _RegistrationPageState extends State<RegistrationPage> {
final _formKey = GlobalKey<FormState>();
bool checkedValue = false;
bool checkboxValue = false;
#override
Widget build(BuildContext context) {
var nameController = TextEditingController();
var emailController = TextEditingController();
var passwordController = TextEditingController();
return Scaffold(
backgroundColor: Colors.white,
body: SingleChildScrollView(
child: Stack(children: [
Container(
height: 150,
child: HeaderWidget(150, false, Icons.person_add_alt_1_rounded),
),
Container(
margin: EdgeInsets.fromLTRB(25, 50, 25, 10),
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
alignment: Alignment.center,
child: Column(
children: [
Form(
key: _formKey,
child: Column(
children: [
GestureDetector(
child: Stack(
children: [
Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
border:
Border.all(width: 5, color: Colors.white),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 20,
offset: const Offset(5, 5),
),
],
),
child: Icon(
Icons.person,
color: Colors.grey.shade300,
size: 80.0,
),
),
Container(
padding: EdgeInsets.fromLTRB(80, 80, 0, 0),
child: Icon(
Icons.add_circle,
color: Colors.grey.shade700,
size: 25.0,
),
),
],
),
),
SizedBox(
height: 30,
),
Container(
child: TextFormField(
controller: nameController,
decoration: ThemeHelper().textInputDecoration(
'Full Name', 'Enter your full name'),
),
decoration: ThemeHelper().inputBoxDecorationShaddow(),
),
SizedBox(
height: 30,
),
SizedBox(height: 20.0),
Container(
child: TextFormField(
controller: emailController,
decoration: ThemeHelper().textInputDecoration(
"E-mail address", "Enter your email"),
keyboardType: TextInputType.emailAddress,
validator: (val) {
// ignore: prefer_is_not_empty
if (!(val!.isEmpty) &&
!RegExp(r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+#[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?)*$")
.hasMatch(val)) {
return "Enter a valid email address";
}
return null;
},
),
decoration: ThemeHelper().inputBoxDecorationShaddow(),
),
SizedBox(height: 20.0),
Container(
child: TextFormField(
obscureText: true,
controller: passwordController,
decoration: ThemeHelper().textInputDecoration(
"Password*", "Enter your password"),
validator: (val) {
if (val!.isEmpty) {
return "Please enter your password";
}
return null;
},
),
decoration: ThemeHelper().inputBoxDecorationShaddow(),
),
SizedBox(height: 15.0),
FormField<bool>(
builder: (state) {
return Column(
children: <Widget>[
Row(
children: <Widget>[
Checkbox(
value: checkboxValue,
onChanged: (value) {
setState(() {
checkboxValue = value!;
state.didChange(value);
});
}),
Text(
"I accept all terms and conditions.",
style: TextStyle(color: Colors.grey),
),
],
),
Container(
alignment: Alignment.centerLeft,
child: Text(
state.errorText ?? '',
textAlign: TextAlign.left,
style: TextStyle(
color: Theme.of(context).errorColor,
fontSize: 12,
),
),
)
],
);
},
validator: (value) {
if (!checkboxValue) {
return 'You need to accept terms and conditions';
} else {
return null;
}
},
),
SizedBox(height: 20.0),
GestureDetector(
onTap: () {
AuthController.instance.register(
nameController.text.trim(),
emailController.text.trim(),
passwordController.text.trim());
},
),
Container(
decoration: ThemeHelper().buttonBoxDecoration(context),
child: ElevatedButton(
style: ThemeHelper().buttonStyle(),
child: Padding(
padding: const EdgeInsets.fromLTRB(40, 10, 40, 10),
child: Text(
"Register".toUpperCase(),
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
onPressed: () {
if (_formKey.currentState!.validate()) {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) => ProfilePage()),
(Route<dynamic> route) => false);
}
},
),
),
SizedBox(height: 30.0),
Text(
"Or create account using social media",
style: TextStyle(color: Colors.grey),
),
SizedBox(height: 25.0),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
child: FaIcon(
FontAwesomeIcons.google,
size: 35,
color: HexColor("#EC2D2F"),
),
onTap: () {
setState(() {
showDialog(
context: context,
builder: (BuildContext context) {
return ThemeHelper().alartDialog(
"Google Account",
"You tap on Google icon.",
context);
},
);
});
},
),
],
),
],
),
),
],
),
),
]),
),
);
}
}
If you guys see more error on my code, please tell me because I'm very clueless about this. Thank you in advance!
The issue occurs from Stack the one inside
Column(
children: [
Form(
key: _formKey,
child: Column(
children: [
GestureDetector(
child: Stack( // this one
Can be fixed by providing hight
GestureDetector(
child: SizedBox(
height: MediaQuery.of(context).size.height, //this based on your need
child: Stack(
I think you can re struct the widget and don't need to use multi-Stack.
More about /ui/layout and Unbounded height / width
I have created a page where user can input their exam result which are subject and grade.
On the page, user need to click the add subject button to add another subject depending on how many subject they have. User also can remove subject by clicking the remove subject button.
The problem is only TextFormField value submitted. How to get the data for DropDownFormField if the form created dynamically?
I have tried the read the data using the onChanged function of the drop down and yes the data was stored to the variable gradeController but it returns null when I submit the data.
This is the model
class SubjectGrade {
final String? name;
final String? grade;
SubjectGrade(this.name, this.grade);
#override
String toString() {
return 'SPM: name = $name, grade = $grade';
}
}
This is the form
import 'package:flutter/material.dart';
import 'package:testing_app/models/education_model.dart';
class EducationBackgroundForm extends StatefulWidget {
const EducationBackgroundForm({Key? key}) : super(key: key);
#override
_EducationBackgroundFormState createState() =>
_EducationBackgroundFormState();
}
class _EducationBackgroundFormState extends State<EducationBackgroundForm> {
final nameTECs = <TextEditingController>[];
final gradeTECs = <String?>[];
final forms = <Form>[];
Form createForm() {
TextEditingController nameController = TextEditingController();
String? gradeController;
nameTECs.add(nameController);
gradeTECs.add(gradeController);
final grades = ['A+', 'A', 'A-', 'B+', 'B', 'C+', 'C', 'D', 'E', 'G'];
DropdownMenuItem<String> buildMenuItem(String item) => DropdownMenuItem(
value: item,
child: Text(item),
);
return Form(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Row(
children: <Widget>[
Expanded(
flex: 2,
child: Column(
children: <Widget>[
TextFormField(
controller: nameController,
decoration: InputDecoration(
hintText: 'Subject Name',
labelText: 'Subject ${forms.length + 1}',
border: const OutlineInputBorder(),
contentPadding:
const EdgeInsets.only(left: 8, right: 8),
),
keyboardType: TextInputType.text,
textInputAction: TextInputAction.done,
),
],
),
),
const SizedBox(width: 5),
Expanded(
flex: 1,
child: Column(
children: <Widget>[
DropdownButtonHideUnderline(
child: DropdownButtonFormField(
value: gradeController,
isExpanded: true,
iconSize: 36,
icon: const Icon(Icons.arrow_drop_down,
color: Colors.black),
items: grades.map(buildMenuItem).toList(),
onChanged: (String? value) {
setState(() {
gradeController = value;
});
},
hint: const Text("Grade"),
decoration: const InputDecoration(
border: OutlineInputBorder(),
contentPadding: EdgeInsets.only(left: 8),
),
),
)
],
)),
],
),
const SizedBox(height: 10)
],
),
);
}
#override
void initState() {
super.initState();
forms.add(createForm());
}
saveSPMResultToFirebase() {
List<SubjectGrade> entries = [];
for (int i = 0; i < forms.length; i++) {
final name = nameTECs[i].text;
final grade = gradeTECs[i].toString();
entries.add(SubjectGrade(name, grade));
}
debugPrint(entries.toString());
//Navigator.pop(context, entries);
}
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const Text("SPM Result", style: TextStyle(fontSize: 18)),
const SizedBox(height: 20),
Expanded(
child: ListView.builder(
itemCount: forms.length,
itemBuilder: (BuildContext context, int index) {
return forms[index];
},
),
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8))),
onPressed: () => setState(() {
forms.add(createForm());
}),
child: const Text(
'Add Subject',
style: TextStyle(
fontSize: 16,
),
),
),
),
),
const SizedBox(width: 5),
Expanded(
child: SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8))),
onPressed: () => setState(() {
if (forms.length > 1) {
forms.removeAt(forms.length - 1);
}
}),
child: const Text(
'Remove Subject',
style: TextStyle(
fontSize: 16,
),
),
),
),
),
],
),
const SizedBox(height: 10),
SizedBox(
width: double.infinity,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8))),
onPressed: () {
saveSPMResultToFirebase();
},
child: const Text(
'Update',
style: TextStyle(
fontSize: 16,
),
),
),
),
],
);
}
}
When I submit the form, the debug output I get from the submit function for grade is null.
Output:
[SPM: name = English, grade = null]
You should add value of DropDownButton in onChanged method not at top of create form.
change your code to this:
First Delete gradeTECs.add(gradeController); line from top of createForm().
Form createForm() {
TextEditingController nameController = TextEditingController();
String? gradeController;
nameTECs.add(nameController);
// gradeTECs.add(gradeController); <==== DELETE THIS LINE.
Add gradeTECs.add(gradeontroller); in onChanged method of DropdownButtonFormField
DropdownButtonHideUnderline(
child: DropdownButtonFormField(
value: gradeController,
isExpanded: true,
iconSize: 36,
icon: const Icon(Icons.arrow_drop_down,
color: Colors.black),
items: grades.map(buildMenuItem).toList(),
onChanged: (String? value) {
setState(() {
gradeController = value;
gradeTECs.add(gradeController); <=== ADD HERE ==>
});
},
hint: const Text("Grade"),
decoration: const InputDecoration(
border: OutlineInputBorder(),
contentPadding: EdgeInsets.only(left: 8),
),
),
),
I am trying to come up with a code editor which takes input from a text form field and shows the output on a Rich Text widget using DartSyntaxHighlighter.
While it works fine for a short snippet of code, it doesn't show all the code for a larger snippet. Here's what I've done so far :
class CodeEditorWidget extends StatefulWidget {
CodeEditorWidget();
#override
_ContentWidgetState createState() {
return _ContentWidgetState();
}
}
class _ContentWidgetState extends BaseState<CodeEditorWidget> {
String _currentCode = "";
#override
void initializeData() {
_currentCode = "class HelloWorld {\n"
"public static void main() {\n"
"System.out.println(\"Hello again\");\n"
"}\n"
"}";
_contentController.addListener(() {
_currentCode = _contentController.value.text;
setState(() {
});
});
}
#override
Widget build(BuildContext context) => _buildContent();
Widget _buildContent() {
//return _buildBody();
userState = AppStateWidget.of(context).userState;
return _buildBody();
}
Scaffold _buildBody() => Scaffold(
key: _scaffoldLoginKey,
appBar: buildAppBar("Code Editor"),
body: _buildCodeEditor(),
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
floatingActionButton: _buildFab(),
);
_buildCodeEditor() => Card(
margin: const EdgeInsets.fromLTRB(BaseState.horizontalMargin, 0, BaseState.horizontalMargin, 0),
child: Column(
children: <Widget>[
Expanded(
child: _buildCodeView()//buildSyntaxCodeBlock(_currentCode, 12)//_buildCodeView(),
),
_buildInputContainer()
],
),
);
_buildCodeView() => SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Container(
width: double.infinity,
height: double.maxFinite,
padding: EdgeInsets.all(12),
decoration: BoxDecoration(color: Colors.black),
child: RichText(
text: TextSpan(
style: TextStyle(fontFamily: 'VarelaRound-Regular', fontSize: 12),
children: <TextSpan>[
DartSyntaxHighlighter(SyntaxHighlighterStyle.darkThemeStyle()).format(_currentCode)
],
),
),
),
),
);
Container _buildInputContainer() {
return Container(
color: Colors.grey,
padding: EdgeInsets.all(8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_buildInputLayout(),
],
),
);
}
_buildInputLayout() => Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[_buildTextForm()],
);
Widget _buildTextForm() => Flexible(
child: Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: TextFormField(
style: buildTextStyleBlack(16),
decoration: InputDecoration.collapsed(hintText: "Type here..."),
maxLines: 10,
validator: _validateEmptyCode,
controller: _contentController,
keyboardType: TextInputType.multiline,
onSaved: (String contentString) {
//_currentCode = contentString;
},
),
),
),
);
String _validateEmptyCode(String value) {
return value.isEmpty ? "Required" : null;
}
var _contentController = TextEditingController();
_buildFab() => FloatingActionButton(
onPressed: () {
setState(() {
});
},
child: Icon(Icons.add),
foregroundColor: Colors.white,
backgroundColor: Colors.green,
);
var _scaffoldLoginKey = GlobalKey<ScaffoldState>();
_showSnackBar(String message) => _scaffoldLoginKey.currentState
.showSnackBar(SnackBar(content: Text(message, style: buildTextStyle(16),)));
}
Here's a screen shot for reference :
This is a web page I am trying to build in flutter.
For me, this piece of code is doing what you are trying to acheive.
TextEditingController text1Controller = new TextEditingController();
TextEditingController text2Controller = new TextEditingController();
#override
Widget build(BuildContext context) {
Size screenSize = MediaQuery.of(context).size;
return new Scaffold(
backgroundColor: Colors.white,
appBar: new PreferredSize(
preferredSize: new Size(screenSize.width, 55.0),
child: new AppBar(
elevation: 5.0,
title : new Text(
"Code Editor",
style: new TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 18.0)),
centerTitle: true,
backgroundColor: Colors.blue,
),
),
body: Container(
child: Column(
children: <Widget>[
new Padding(padding: EdgeInsets.only(bottom: 20.0, top: 20.0)),
new TextField(
onChanged: (text) {
setState(() {
text2Controller.text = text;
});
},
controller: text1Controller,
keyboardType: TextInputType.text,
autofocus: false,
decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
focusedBorder: OutlineInputBorder(borderSide: const BorderSide(color: Colors.black, width: 2.0)),
),
),
new Padding(padding: EdgeInsets.only(bottom: 20.0)),
new TextField(
controller: text2Controller,
keyboardType: TextInputType.text,
autofocus: false,
decoration: InputDecoration(
contentPadding: EdgeInsets.fromLTRB(20.0, 10.0, 20.0, 10.0),
focusedBorder: OutlineInputBorder(borderSide: const BorderSide(color: Colors.black, width: 2.0)),
),
)
],),),
);
}