I'm opening up a form to enter the details and close it upon filling everything and submitting it, but only the trailing icon is getting changed, also I'm trying to set the changes in the onExpansionChanged but not reflecting in the UI.
Updated Code
Scaffold(
backgroundColor: Colors.grey.shade200,
appBar: AppBar(
title: TextButton(
child: Text(count.toString()),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (_) => RegisterLetterBookedListScreen()));
},
),
backgroundColor: ColorConstants.kPrimaryColor,
elevation: 0,
),
floatingActionButton: FloatingActionButton(
onPressed: () {
MotionToast.success(
title: 'Amount to be Collected',
titleStyle: TextStyle(fontWeight: FontWeight.bold),
description: '\u{20B9} $amountToBeCollected',
descriptionStyle: TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
layoutOrientation: ORIENTATION.LTR,
animationType: ANIMATION.FROM_LEFT,
width: 300,
).show(context);
},
child: Text(
'\u{20B9} $amountToBeCollected',
style: TextStyle(fontSize: 20),
),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//Article Details
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//Sender Details
ExpansionTile(
key: GlobalKey(),
trailing: (senderExpansion == false)
? Icon(
MdiIcons.toggleSwitchOffOutline,
size: 40,
color: Colors.black54,
)
: Icon(MdiIcons.toggleSwitchOutline, size: 40, color: Colors.red),
onExpansionChanged: (value) {
senderExpansion = value;
},
maintainState: true,
initiallyExpanded: senderExpansion,
title: Text(
'Sender Details',
style: TextStyle(
fontWeight: FontWeight.bold,
color: senderHeadingColor,
fontSize: 20,
letterSpacing: 1),
),
children: [
Column(
children: [
CInputForm(
readOnly: false,
iconData: Icons.person,
labelText: 'Name *',
controller: senderNameController,
textType: TextInputType.text,
typeValue: 'Name',
focusNode: senderNameFocusNode,
),
CInputForm(
readOnly: false,
iconData: MdiIcons.home,
labelText: 'Address *',
controller: senderAddressController,
textType: TextInputType.multiline,
typeValue: 'Address',
focusNode: senderAddressFocusNode,
),
Card(
elevation: 0,
child: TypeAheadFormField(
textFieldConfiguration: TextFieldConfiguration(
style: TextStyle(color: Colors.blueGrey),
controller: senderPinCodeCityController,
autofocus: false,
decoration: InputDecoration(
prefixIcon: Icon(
Icons.location_on_outlined,
color: Colors.blueGrey,
),
fillColor: Colors.white,
filled: true,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
),
labelText: 'Pincode/Office Name *',
labelStyle: TextStyle(
color: ColorConstants.kAmberAccentColor),
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white)))),
onSuggestionSelected:
(Map<String, String> suggestion) async {
senderPinCodeCityController.text = suggestion['pinCode']!;
senderCityController.text = suggestion['city']!;
senderStateController.text = suggestion['state']!;
},
itemBuilder: (context, Map<String, String> suggestion) {
return ListTile(
title: Text(suggestion['officeName']! +
", " +
suggestion['pinCode']!),
);
},
suggestionsCallback: (pattern) async {
return await FetchPin.getSuggestions(pattern);
},
validator: (value) {
if (value!.isEmpty) {
issPin = false;
isLoading = false;
}
},
),
),
Visibility(
visible: issPin == false ? senderPinCodeCityController.text.isEmpty ? true : false : false,
child: Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.only(left: 17.0),
child: Text('Select a Pincode/Office name', style: TextStyle(fontSize: 10, color: ColorConstants.kPrimaryColor),),
)),
),
Visibility(
visible:
senderPinCodeCityController.text.isEmpty ? false : true,
child: CInputForm(
readOnly: true,
iconData: Icons.location_city,
labelText: 'City',
controller: senderCityController,
textType: TextInputType.text,
typeValue: 'City',
focusNode: senderPinCodeFocusNode,
),
),
Visibility(
visible:
senderPinCodeCityController.text.isEmpty ? false : true,
child: CInputForm(
readOnly: true,
iconData: Icons.location_city,
labelText: 'State',
controller: senderStateController,
textType: TextInputType.text,
typeValue: 'City',
focusNode: senderPinCodeFocusNode,
),
),
CInputForm(
readOnly: false,
iconData: MdiIcons.cellphone,
labelText: 'Mobile Number',
controller: senderMobileNumberController,
textType: TextInputType.number,
typeValue: 'MobileNumber',
focusNode: senderMobileFocusNode,
),
CInputForm(
readOnly: false,
iconData: MdiIcons.email,
labelText: 'Email',
controller: senderEmailController,
textType: TextInputType.emailAddress,
typeValue: 'Email',
focusNode: senderEmailFocusNode,
),
],
)
],
),
//Addressee Details
ExpansionTile(
trailing: (addresseeExpansion == false)
? Icon(
MdiIcons.toggleSwitchOffOutline,
size: 40,
color: Colors.black54,
)
: Icon(MdiIcons.toggleSwitchOutline, size: 40, color: Colors.red),
onExpansionChanged: (value) {
addresseeExpansion = value;
},
maintainState: true,
title: Text('Addressee Details',
style: TextStyle(
fontWeight: FontWeight.bold,
color: addresseeHeadingColor,
fontSize: 20,
letterSpacing: 1)),
children: [
Column(
children: [
CInputForm(
readOnly: false,
iconData: Icons.person,
labelText: 'Name *',
controller: addresseeNameController,
textType: TextInputType.text,
typeValue: 'Name',
focusNode: addresseeNameFocusNode,
),
CInputForm(
readOnly: false,
iconData: MdiIcons.home,
labelText: 'Address *',
controller: addresseeAddressController,
textType: TextInputType.multiline,
typeValue: 'Address',
focusNode: addresseeAddressFocusNode,
),
Card(
elevation: 0,
child: TypeAheadFormField(
textFieldConfiguration: TextFieldConfiguration(
style: TextStyle(color: Colors.blueGrey),
controller: addresseePinCodeCityController,
autofocus: false,
decoration: InputDecoration(
prefixIcon: Icon(
Icons.location_on_outlined,
color: Colors.blueGrey,
),
fillColor: Colors.white,
filled: true,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white),
),
labelText: 'Pincode/Office Name *',
labelStyle: TextStyle(
color: ColorConstants.kAmberAccentColor),
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white)))),
onSuggestionSelected:
(Map<String, String> suggestion) async {
addresseePinCodeCityController.text =
suggestion['pinCode']!;
addresseeCityController.text = suggestion['city']!;
addresseeStateController.text = suggestion['state']!;
},
itemBuilder: (context, Map<String, String> suggestion) {
return ListTile(
title: Text(suggestion['officeName']! +
", " +
suggestion['pinCode']!),
);
},
suggestionsCallback: (pattern) async {
return await FetchPin.getSuggestions(pattern);
},
validator: (value) {
if (value!.isEmpty) {
isLoading = false;
isaPin = false;
}
},
),
),
Visibility(
visible: isaPin == false ? addresseePinCodeCityController.text.isEmpty ? true : false : false,
child: Align(
alignment: Alignment.topLeft,
child: Padding(
padding: const EdgeInsets.only(left: 17.0),
child: Text('Select a Pincode/Office name', style: TextStyle(fontSize: 10, color: ColorConstants.kPrimaryColor),),
)),
),
Visibility(
visible: addresseePinCodeCityController.text.isEmpty
? false
: true,
child: CInputForm(
readOnly: true,
iconData: Icons.location_city,
labelText: 'City',
controller: addresseeCityController,
textType: TextInputType.text,
typeValue: 'City',
focusNode: addresseePinCodeFocusNode,
),
),
Visibility(
visible: addresseePinCodeCityController.text.isEmpty
? false
: true,
child: CInputForm(
readOnly: true,
iconData: Icons.location_city,
labelText: 'State',
controller: addresseeStateController,
textType: TextInputType.text,
typeValue: 'State',
focusNode: addresseePinCodeFocusNode,
),
),
CInputForm(
readOnly: false,
iconData: MdiIcons.cellphone,
labelText: 'Mobile Number',
controller: addresseeMobileNumberController,
textType: TextInputType.number,
typeValue: 'MobileNumber',
focusNode: addresseeMobileFocusNode,
),
CInputForm(
readOnly: false,
iconData: MdiIcons.email,
labelText: 'Email',
controller: addresseeEmailController,
textType: TextInputType.emailAddress,
typeValue: 'Email',
focusNode: addresseeEmailFocusNode,
),
],
),
],
),
//Submit
Padding(
padding: const EdgeInsets.all(8.0),
child: Center(
child: ElevatedButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all<Color>(Colors.white),
shape: MaterialStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
side: BorderSide(color: Colors.blueGrey)))),
onPressed: () async {
setState(() {
senderExpansion = !senderExpansion;
addresseeExpansion = !addresseeExpansion;
});
final ifPresent = await RegisterLetterTable()
.select()
.ArticleNumber
.equals(articleNumberController.text)
.toMapList();
if (ifPresent.isNotEmpty) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Article already scanned'),
behavior: SnackBarBehavior.floating,
));
} else {
if (articleNumberController.text.isEmpty) {
setState(() {
articleNumberFocusNode.requestFocus();
});
} else if (weightController.text.isEmpty) {
setState(() {
weightFocusNode.requestFocus();
});
} else if (insuranceCheck == true) {
if (insuranceController.text.isEmpty)
insuranceFocusNode.requestFocus();
} else if (valuePayableCheck == true) {
if (valuePayablePostController.text.isEmpty)
valuePayableFocusNode.requestFocus();
}
if (senderNameController.text.isEmpty ||
senderAddressController.text.isEmpty ||
senderPinCodeCityController.text.isEmpty) {
setState(() {
senderExpansion = true;
});
if (addresseeNameController.text.isEmpty ||
addresseeAddressController.text.isEmpty ||
addresseePinCodeCityController.text.isEmpty) {
setState(() {
addresseeExpansion = true;
});
} else
setState(() {
addresseeExpansion = false;
});
} else
senderExpansion = false;
if (addresseeNameController.text.isEmpty ||
addresseeAddressController.text.isEmpty ||
addresseePinCodeCityController.text.isEmpty) {
setState(() {
addresseeExpansion = true;
});
} else
setState(() {
addresseeExpansion = false;
});
if (formGlobalKey.currentState!.validate()) {
formGlobalKey.currentState!.save();
showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return ConformationDialog(
articleNumber: articleNumberController.text,
weight: weightController.text,
prepaidAmount: prepaidAmountController.text,
acknowledgement: acknowledgementCheck,
insurance: insuranceCheck == true
? insuranceController.text
: '',
valuePayablePost: valuePayableCheck == true
? valuePayablePostController.text
: '',
amountToBeCollected:
amountToBeCollectedController.text,
senderName: senderNameController.text,
senderAddress: senderAddressController.text,
senderPinCode: senderPinCodeCityController.text,
senderCity: senderCityController.text,
senderState: senderStateController.text,
senderMobileNumber:
senderMobileNumberController.text,
senderEmail: senderEmailController.text,
addresseeName: addresseeNameController.text,
addresseeAddress: addresseeAddressController.text,
addresseePinCode:
addresseePinCodeCityController.text,
addresseeCity: addresseeCityController.text,
addresseeState: addresseeStateController.text,
addresseeMobileNumber:
addresseeMobileNumberController.text,
addresseeEmail: addresseeEmailController.text,
function: () {
Navigator.of(context).pop();
printFunction();
});
});
}
}
},
child: Padding(
padding: const EdgeInsets.all(8.0),
child: new Text(
'SUBMIT',
overflow: TextOverflow.ellipsis,
style: TextStyle(color: ColorConstants.kAmberAccentColor),
),
),
),
),
)
],
),
),
))
checkout below code it may help you,
class TestExpanTile extends StatefulWidget {
#override
TestExpanTileState createState() => new TestExpanTileState();
}
class TestExpanTileState extends State<TestExpanTile> {
String senderDet = 'Sender Details ';
bool formOpenFlag = true;
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: const Text('ExpansionTile'),
),
body: new ExpansionTile(
key: GlobalKey(),
initiallyExpanded: formOpenFlag,
onExpansionChanged: (val) {
formOpenFlag = val; // update here on change
},
title: new Text(this.senderDet),
backgroundColor: Theme.of(context).accentColor.withOpacity(0.025),
children: <Widget>[
new ListTile(
title: const Text('Your Filling Form goes here'),
onTap: () {},
),
RaisedButton(
onPressed: () {
setState(() {
formOpenFlag = !formOpenFlag;
});
},
child: Text("Close Tile On Submit"),
)
],
),
),
);
}
}
Since your using Multiple ExpansionTiles, as said by #Jai Techie you need a key to control its state, but as per my knowledge we cannot provide the state of the ExpansionTile as the GlobalKey, so in order to acheive it create a new CustomExpansionTile.
import 'package:flutter/material.dart';
class FormExpansionTileCard extends StatefulWidget {
const FormExpansionTileCard({
Key? key,
this.leading,
required this.title,
this.subtitle,
this.onExpansionChanged,
this.children = const <Widget>[],
this.trailing,
this.borderRadius = const BorderRadius.all(Radius.circular(8.0)),
this.elevation = 2.0,
this.initialElevation = 0.0,
this.initiallyExpanded = false,
this.initialPadding = EdgeInsets.zero,
this.finalPadding = const EdgeInsets.only(bottom: 6.0),
this.contentPadding,
this.baseColor,
this.expandedColor,
this.expandedTextColor,
this.duration = const Duration(milliseconds: 200),
this.elevationCurve = Curves.easeOut,
this.heightFactorCurve = Curves.easeIn,
this.turnsCurve = Curves.easeIn,
this.colorCurve = Curves.easeIn,
this.paddingCurve = Curves.easeIn,
this.isThreeLine = false,
this.shadowColor = const Color(0xffaaaaaa),
this.animateTrailing = false,
}) : assert(initiallyExpanded != null),
super(key: key);
final bool isThreeLine;
final Widget? leading;
final Widget title;
final Widget? subtitle;
final ValueChanged<bool>? onExpansionChanged;
final List<Widget> children;
final Widget? trailing;
final bool animateTrailing;
final BorderRadiusGeometry borderRadius;
final double elevation;
final double initialElevation;
final Color shadowColor;
final bool initiallyExpanded;
final EdgeInsetsGeometry initialPadding;
final EdgeInsetsGeometry finalPadding;
final EdgeInsetsGeometry? contentPadding;
final Color? baseColor;
final Color? expandedColor;
final Color? expandedTextColor;
final Duration duration;
final Curve elevationCurve;
final Curve heightFactorCurve;
final Curve turnsCurve;
final Curve colorCurve;
final Curve paddingCurve;
#override
FormExpansionTileCardState createState() => FormExpansionTileCardState();
}
class FormExpansionTileCardState extends State<FormExpansionTileCard>
with SingleTickerProviderStateMixin {
static final Animatable<double> _halfTween =
Tween<double>(begin: 0.0, end: 0.5);
final ColorTween _headerColorTween = ColorTween();
final ColorTween _iconColorTween = ColorTween();
final ColorTween _materialColorTween = ColorTween();
late EdgeInsetsTween _edgeInsetsTween;
late Animatable<double> _elevationTween;
late Animatable<double> _heightFactorTween;
late Animatable<double> _turnsTween;
late Animatable<double> _colorTween;
late Animatable<double> _paddingTween;
late AnimationController _controller;
late Animation<double> _iconTurns;
late Animation<double> _heightFactor;
late Animation<double> _elevation;
late Animation<Color?> _headerColor;
late Animation<Color?> _iconColor;
late Animation<Color?> _materialColor;
late Animation<EdgeInsets> _padding;
bool _isExpanded = false;
#override
void initState() {
super.initState();
_edgeInsetsTween = EdgeInsetsTween(
begin: widget.initialPadding as EdgeInsets?,
end: widget.finalPadding as EdgeInsets?,
);
_elevationTween = CurveTween(curve: widget.elevationCurve);
_heightFactorTween = CurveTween(curve: widget.heightFactorCurve);
_colorTween = CurveTween(curve: widget.colorCurve);
_turnsTween = CurveTween(curve: widget.turnsCurve);
_paddingTween = CurveTween(curve: widget.paddingCurve);
_controller = AnimationController(duration: widget.duration, vsync: this);
_heightFactor = _controller.drive(_heightFactorTween);
_iconTurns = _controller.drive(_halfTween.chain(_turnsTween));
_headerColor = _controller.drive(_headerColorTween.chain(_colorTween));
_materialColor = _controller.drive(_materialColorTween.chain(_colorTween));
_iconColor = _controller.drive(_iconColorTween.chain(_colorTween));
_elevation = _controller.drive(
Tween<double>(begin: widget.initialElevation, end: widget.elevation)
.chain(_elevationTween));
_padding = _controller.drive(_edgeInsetsTween.chain(_paddingTween));
_isExpanded = PageStorage.of(context)?.readState(context) as bool? ??
widget.initiallyExpanded;
if (_isExpanded) _controller.value = 1.0;
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
// Credit: Simon Lightfoot - https://stackoverflow.com/a/48935106/955974
void _setExpansion(bool shouldBeExpanded) {
if (shouldBeExpanded != _isExpanded) {
setState(() {
_isExpanded = shouldBeExpanded;
if (_isExpanded) {
_controller.forward();
} else {
_controller.reverse().then<void>((void value) {
if (!mounted) return;
setState(() {
// Rebuild without widget.children.
});
});
}
PageStorage.of(context)?.writeState(context, _isExpanded);
});
if (widget.onExpansionChanged != null)
widget.onExpansionChanged!(_isExpanded);
}
}
void expand() {
_setExpansion(true);
}
void collapse() {
_setExpansion(false);
}
void toggleExpansion() {
_setExpansion(!_isExpanded);
}
Widget _buildChildren(BuildContext context, Widget? child) {
return Padding(
padding: _padding.value,
child: Material(
color: Colors.grey[200],
borderRadius: widget.borderRadius,
elevation: 0,
shadowColor: widget.shadowColor,
child: Container(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
InkWell(
customBorder:
RoundedRectangleBorder(borderRadius: widget.borderRadius),
onTap: toggleExpansion,
child: ListTileTheme.merge(
iconColor: _iconColor.value,
textColor: _headerColor.value,
child: Padding(
padding: const EdgeInsets.all(2.0),
child: ListTile(
isThreeLine: widget.isThreeLine,
contentPadding: widget.contentPadding,
leading: widget.leading,
title: widget.title,
subtitle: widget.subtitle,
trailing: RotationTransition(
turns: widget.trailing == null || widget.animateTrailing
? _iconTurns
: AlwaysStoppedAnimation(0),
child: widget.trailing ?? Icon(Icons.expand_more),
),
),
),
),
),
ClipRect(
child: Align(
heightFactor: _heightFactor.value,
child: child,
),
),
],
),
),
),
);
}
#override
void didChangeDependencies() {
final ThemeData theme = Theme.of(context);
_headerColorTween
..begin = theme.textTheme.subtitle1!.color
..end = widget.expandedTextColor ?? theme.accentColor;
_iconColorTween
..begin = theme.unselectedWidgetColor
..end = widget.expandedTextColor ?? theme.accentColor;
_materialColorTween
..begin = widget.baseColor ?? theme.canvasColor
..end = widget.expandedColor ?? theme.cardColor;
super.didChangeDependencies();
}
#override
Widget build(BuildContext context) {
final bool closed = !_isExpanded && _controller.isDismissed;
return AnimatedBuilder(
animation: _controller.view,
builder: _buildChildren,
child: closed ? null : Column(children: widget.children),
);
}
}
Initialize the key value in your dart file
final GlobalKey<FormExpansionTileCardState> cardA = new GlobalKey();
final GlobalKey<FormExpansionTileCardState> cardB = new GlobalKey();
//Sender Details
FormExpansionTileCard(
key: cardA,
trailing: (senderExpansion == false)
? Icon(
MdiIcons.toggleSwitchOffOutline,
size: 40,
color: Colors.black54,
)
: Icon(MdiIcons.toggleSwitchOutline, size: 40, color: Colors.red),
onExpansionChanged: (value) {
senderExpansion = value;
},
initiallyExpanded: senderExpansion,
title: Text(
'Sender Details',
style: TextStyle(
fontWeight: FontWeight.bold,
color: senderHeadingColor,
fontSize: 20,
letterSpacing: 1),
),
children: [
//...Your Widgets
],
),
//Addressee Details
FormExpansionTileCard(
key: cardB,
trailing: (senderExpansion == false)
? Icon(
MdiIcons.toggleSwitchOffOutline,
size: 40,
color: Colors.black54,
)
: Icon(MdiIcons.toggleSwitchOutline, size: 40, color: Colors.red),
onExpansionChanged: (value) {
addresseeExpansion = value;
},
initiallyExpanded: addresseeExpansion,
title: Text(
'AddresseeDetails',
style: TextStyle(
fontWeight: FontWeight.bold,
color: senderHeadingColor,
fontSize: 20,
letterSpacing: 1),
),
children: [
//...Your Widgets
],
),
I created a simple solution to this very problem. Hope this helps.
Solution: https://github.com/TreyThomas93/flutter-expansion-tile-demo
Related
I amm using two languages in my flutter, English and Arabic, when user select his city(cities will show in DropdownMenu) while registering in English language it works fine, he can update his profile by changing his city but when same user change language from English to Arabic and go to his profile section I get error.
How can I resolve this issue?
There should be exactly one item with [DropdownButton]'s value: Dubai. Either zero or 2 or more [DropdownMenuItem]s were detected with the same value 'package:flutter/src/material/dropdown.dart': Failed assertion: line 1580 pos 15: 'items == null || items.isEmpty || value == null || items.where((DropdownMenuItem<T> item) { return item.value == value; }).length == 1'
This error popup when English user change to Arabic language, and same when Arabic user change to English language.
Here is my Profile update code:
class Profile extends StatefulWidget {
final Function(Map<String, dynamic>) callBack;
const Profile(this.callBack, {Key? key}) : super(key: key);
#override
State<Profile> createState() => _ProfileState();
}
class _ProfileState extends State<Profile> {
List<String> cities = [
LanguageStringKeys.instance.abuDhabi.tr,
LanguageStringKeys.instance.dubai.tr,
LanguageStringKeys.instance.sharjah.tr,
LanguageStringKeys.instance.ajman.tr,
LanguageStringKeys.instance.ummAlQuwain.tr,
LanguageStringKeys.instance.rasAlKhaimah.tr,
LanguageStringKeys.instance.fujairah.tr,
];
String selectedCity = Get.put(AppController()).loginResponse?.data?.user?.address;
var nameController = TextEditingController();
var tradeController = TextEditingController();
var phoneController = TextEditingController();
var bioController = TextEditingController();
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
nameController.text = Get.put(AppController()).loginResponse?.data?.user?.firstName ?? "";
tradeController.text = Get.put(AppController()).loginResponse?.data?.user?.tradeLicense ?? "";
phoneController.text = Get.put(AppController()).loginResponse?.data?.user?.phone ?? "";
selectedCity = Get.put(AppController()).loginResponse?.data?.user?.address ?? "";
bioController.text = Get.put(AppController()).loginResponse?.data?.user?.bio ?? "";
});
}
#override
Widget build(BuildContext context) {
return BackgroundImage(
image: const AssetImage('assets/images/enjyback.png'),
child: GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Scaffold(
backgroundColor: Colors.transparent,
body: Center(
child: SingleChildScrollView(
physics: const BouncingScrollPhysics(),
child: Padding(
padding: EdgeInsets.symmetric(horizontal: Dimensions.width20, vertical: Dimensions.height10),
child: Column(
children: [
AppTextField(
textController: nameController,
labelText: LanguageStringKeys.instance.name.tr,
labelColor: Colors.white,
borderColor: Colors.white,
textColor: Colors.white,
inputType: TextInputType.name,
),
SizedBox(height: Dimensions.height15),
AppTextField(
textController: tradeController,
labelText: LanguageStringKeys.instance.tradeLicenseNo.tr,
labelColor: Colors.white,
borderColor: Colors.white,
textInputFormatter: 7,
textColor: Colors.white,
inputType: TextInputType.number,
),
SizedBox(height: Dimensions.height15),
AppTextField(
textController: phoneController,
labelText: LanguageStringKeys.instance.phoneNumber.tr,
labelColor: Colors.white,
borderColor: Colors.white,
textColor: Colors.white,
inputType: TextInputType.number,
),
SizedBox(height: Dimensions.height15),
ButtonTheme(
alignedDropdown: true,
child: DropdownButtonFormField(
isExpanded: true,
borderRadius: BorderRadius.circular(Dimensions.height10),
iconEnabledColor: Colors.white,
selectedItemBuilder: (BuildContext context) {
return cities
.map((e) => Text(
selectedCity,
style: const TextStyle(color: Colors.white),
))
.toList();
},
decoration: textFormFieldsDecoration(
LanguageStringKeys.instance.city.tr,
Colors.white,
Colors.white,
),
items: cities
.map((item) => DropdownMenuItem(
value: item,
child: SmallText(text: item, color: Colors.black),
))
.toList(),
value: selectedCity,
onChanged: (item) => setState(() => selectedCity = item as String)),
),
SizedBox(height: Dimensions.height15),
AppTextField(
textController: bioController,
labelText: LanguageStringKeys.instance.bio.tr,
labelColor: Colors.white,
textColor: Colors.white,
maxLines: 6,
borderColor: Colors.white,
inputType: TextInputType.name,
),
SizedBox(height: Dimensions.height15),
ElevatedButton(
onPressed: () {
Provider.of<UserProfileService>(context, listen: false).updateUserProfile(context, {}, {
"name": nameController.text,
"trade_license": tradeController.text,
"phone": phoneController.text,
"address": selectedCity,
"bio": bioController.text,
"image": image,
});
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(Dimensions.radius10)),
minimumSize: Size.fromHeight(Dimensions.height40),
),
child: SmallText(text: LanguageStringKeys.instance.save.tr, color: Colors.grey),
),
SizedBox(height: Dimensions.height15),
],
),
),
),
),
),
),
);
}
}
My product has been added to Firebase, but there is a problem with the dashboard's list not appearing. No errors are displayed on the console or the screen.I'm not sure where the problem is appearing in the code or firebase. I'm basically developing an e-commerce app that users should use to sell their goods.
class _SellerDashBoardState extends State<SellerDashBoard> {
MaterialColor active = Colors.red;
MaterialColor notActive = Colors.grey;
List<SellerProductItem> products = [
const SellerProductItem(),
];
#override
Widget build(BuildContext context) {
print(parentIdGlobal);
print(FirebaseAuth.instance.currentUser!.uid);
return Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBar(
title: Text(
'Seller Dashboard',
style: TextStyle(
fontSize: ResponsiveWidget.isSmallScreen(context) ? 17.0 : 25.0),
),
actions: [
IconButton(
icon: const Icon(Icons.add_circle),
iconSize: 27.0,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => AddProductForm(),
),
);
},
),
IconButton(
icon: WebsafeSvg.asset(
'assets/images/sold-out.svg',
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => SoldItemScreens(),
),
);
},
),
],
),
body: Column(
children: <Widget>[
const SizedBox(
height: 10.0,
),
Container(
color: const Color(0xffF7F7F7),
child: StreamBuilder(
stream: FirebaseFirestore.instance
.collection("items")
.where('seller', isEqualTo: parentIdGlobal)
.where('isSold', isEqualTo: true)
.snapshots(),
builder: (context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator());
}
final List<QueryDocumentSnapshot<Map<String, dynamic>>>
docSnapList = snapshot.data?.docs ?? [];
if (docSnapList.isEmpty) {
return Center(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: WebsafeSvg.asset(
'assets/images/empty_dashboard.svg',
fit: BoxFit.cover,
height: MediaQuery.of(context).size.height / 5,
),
),
);
}
final List<Map<String, dynamic>> docList = docSnapList
.map((QueryDocumentSnapshot<Map<String, dynamic>>
queryDocumentSnapshot) =>
queryDocumentSnapshot.data())
.toList();
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: docList.length,
itemBuilder: (context, index) {
bool isSold = docList[index]['isSold'] ?? true;
bool isLiked = docList[index]['isLiked'] ?? true;
String itemId = docList[index]['itemId'] ?? '';
String seller = docList[index]['seller'] ?? '';
String sellerName = docList[index]['sellerName'] ?? '';
String title = docList[index]['title'] ?? '';
String desc = docList[index]['desc'] ?? '';
String price = docList[index]['price'] ?? '';
String condition = docList[index]['condition'] ?? '';
String category = docList[index]['category'] ?? '';
String location = docList[index]['location'] ?? '';
String itemImage =
docList[index]['imageDownloadUrl'] ?? '';
return SellerProductItem(
itemId: itemId,
seller: seller,
sellerName: sellerName,
title: title,
desc: desc,
price: price,
itemImage: itemImage,
isLiked: isLiked,
isSold: isSold,
category: category,
condition: condition,
location: location,
);
},
);
},
add product screen
class _AddProductFormState extends State<AddProductForm> {
TextEditingController controllerTitle = TextEditingController();
TextEditingController controllerPrice = TextEditingController();
TextEditingController controllerDescription = TextEditingController();
TextEditingController controllerlocation = TextEditingController();
GlobalKey<FormState> _formKey = GlobalKey();
String selectedCondition = 'New';
String selectedCategory = 'Cosmetic Aids';
bool isReadOnly = true;
File? pickedImage;
bool imgStatus = false;
List<String> conditionList = [
'New',
'Like New',
'Good',
'Fair',
'Poor',
];
List<String> categoryList = [
'Cosmetic Aids',
'Mobility Products',
'Bath Safety Products',
'Others',
];
bool _switchValue = false;
Future<void> addGroceryItemToToDb() async {
final itemId = Uuid().v4();
String? url;
if (pickedImage != null) {
print(parentIdGlobal);
print(FirebaseAuth.instance.currentUser!.uid);
Reference storage = FirebaseStorage.instance
.ref()
.child('users/${FirebaseAuth.instance.currentUser!.uid}/$itemId/item_pic');
UploadTask uploadTask = storage.putFile(pickedImage!);
final temp = await (await uploadTask).ref.getDownloadURL();
url = temp.toString();
}
FirebaseFirestore.instance.collection('items').doc(itemId).set(
{
'itemId': itemId,
'timestamp': DateTime.now(),
'seller': parentIdGlobal,
'sellerName': userNameGlobal,
'title': controllerTitle.text,
'price': controllerPrice.text,
'desc': controllerDescription.text,
'condition': selectedCondition,
'category': selectedCategory,
'location': controllerlocation.text,
'isSold': false,
'imageDownloadUrl': url,
},
);
} // adds grocery item to db
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 1.0,
centerTitle: true,
title: Text(
'Add a Product',
),
),
body: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
_selectImageButton(context),
_writeTitle(),
_writePrice(),
_giveitfree(),
_conditionDropDown(),
_writeDescription(),
_categoryDropDown(),
_writeLocation(),
Align(
alignment: Alignment.bottomCenter,
child: _addProductButton(context)),
],
),
),
),
);
}
_selectImageButton(BuildContext context) {
return GestureDetector(
onTap: () async {
await Permission.photos.request();
var status = await Permission.photos.status;
if (status.isGranted) {
try {
XFile? _pickedImage = await ImagePicker().pickImage(
source: ImageSource.gallery,
maxWidth: 100,
maxHeight: 100,
imageQuality: 100
) ;
if(_pickedImage !=null){
pickedImage = File(_pickedImage.path);
setState(() {
imgStatus = true;
});
} }catch (e) {
print(e.toString());
}
} else if (status.isDenied || status.isRestricted) {
print('Permission Denied');
showDialog(
context: context,
builder: (context) {
if (Platform.isAndroid)
return AlertDialog(
title: Text('Permission Not Granted'),
content:
Text('The permission for photo library is not granted'),
actions: [
ElevatedButton(
onPressed: () => openAppSettings(),
child: Text('Ok'),
),
],
);
return CupertinoAlertDialog(
title: Text('Permission Not Granted'),
content:
Text('The permission for photo library is not granted'),
actions: [
ElevatedButton(
onPressed: () => openAppSettings(),
child: Text('Ok'),
),
],
);
});
} else if (status.isDenied) {
print('Permission Undetermined');
}
},
child: Padding(
padding: EdgeInsets.only(
top: 10.0,
bottom: 10.0,
),
child: Container(
height: 100.0,
width: 100.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10.0),
color: Colors.transparent,
border: Border.all(
style: BorderStyle.solid,
color: Colors.red,
),
),
child: pickedImage == null
? Icon(
Icons.add,
color: Colors.red,
)
: Image.file(
pickedImage!,
fit: BoxFit.contain,
),
),
),
);
}
ButtonTheme _addProductButton(BuildContext context) {
return ButtonTheme(
minWidth: MediaQuery.of(context).size.width / 1.1,
child: ElevatedButton(
onPressed: imgStatus
? () async {
if (_formKey.currentState?.validate() == true) {
try {
Navigator.pop(context);
await addGroceryItemToToDb();
} catch (error) {
print(error);
}
}
}
: null,
child: Text(
'Add Product',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
);
}
Padding _writeDescription() {
return Padding(
padding: EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 10.0,
),
child: TextFormField(
controller: controllerDescription,
maxLines: 5,
inputFormatters: [
new LengthLimitingTextInputFormatter(
1450,
),
],
maxLength: 1450,
decoration: InputDecoration(
alignLabelWithHint: true,
isDense: true,
labelText: 'Description',
helperText: "Describe what you're selling in detail",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
),
);
}
Padding _conditionDropDown() {
return Padding(
padding: EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 10.0,
),
child: conditionDropdownbuttonStyle(),
);
}
Widget conditionDropdownbuttonStyle() {
List<Text> pickerItems = [];
for (String condition in conditionList) {
pickerItems.add(Text(condition));
}
if (Platform.isIOS) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Condition',
textAlign: TextAlign.left,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
SizedBox(
height: 10,
),
CupertinoPicker(
backgroundColor: Colors.white70,
useMagnifier: true,
itemExtent: 32.0,
diameterRatio: 2,
scrollController: FixedExtentScrollController(initialItem: 0),
magnification: 1.2,
onSelectedItemChanged: (selectedIndex) {
print(selectedIndex);
selectedCondition = conditionList[selectedIndex];
print(selectedCondition);
},
children: pickerItems,
),
],
);
}
List<DropdownMenuItem<String>> dropDownItem = [];
for (String condition in conditionList) {
print(condition);
var newItem = DropdownMenuItem<String>(
child: Text(condition),
value: condition,
);
dropDownItem.add(newItem);
}
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(
'Condition',
textAlign: TextAlign.left,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
SizedBox(
width: 10.0,
),
Expanded(
child: DropdownButton<String>(
items: dropDownItem,
isExpanded: true,
value: selectedCondition,
hint: Text(
'Condition',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
onChanged: (value) {
setState(() {
if (value != null) {
selectedCondition = value;
}
});
},
),
)
],
);
}
Padding _categoryDropDown() {
return Padding(
padding: EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 10.0,
),
child: categoryDropdownbuttonStyle(),
);
}
Widget categoryDropdownbuttonStyle() {
List<Text> pickerItems1 = [];
for (String category in categoryList) {
pickerItems1.add(Text(category));
}
if (Platform.isIOS) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Category',
textAlign: TextAlign.left,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
SizedBox(
height: 10,
),
CupertinoPicker(
backgroundColor: Colors.white70,
useMagnifier: true,
itemExtent: 32.0,
diameterRatio: 2,
scrollController: FixedExtentScrollController(initialItem: 0),
magnification: 1,
onSelectedItemChanged: (selectedIndex) {
print(selectedIndex);
selectedCategory = categoryList[selectedIndex];
print(selectedCategory);
},
children: pickerItems1,
),
],
);
}
List<DropdownMenuItem<String>> dropDownItem = [];
for (String category in categoryList) {
print(category);
var newItem = DropdownMenuItem<String>(
child: Text(category),
value: category,
);
dropDownItem.add(newItem);
}
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text(
'Category',
textAlign: TextAlign.left,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
SizedBox(
width: 10.0,
),
Expanded(
child: DropdownButton<String>(
items: dropDownItem,
isExpanded: true,
value: selectedCategory,
hint: Text(
'Category',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
onChanged: (value) {
setState(() {
if (value != null) {
selectedCategory = value;}
});
},
),
)
],
);
}
Padding _giveitfree() {
return Padding(
padding: EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 10.0,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'Give it away for free',
maxLines: 1,
style: TextStyle(
fontWeight: FontWeight.w600,
),
),
switchButtonType(),
],
),
);
}
Widget _writePrice() {
if (_switchValue) {
return Container(
width: 0.0,
height: 0.0,
);
}
return Padding(
padding: EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 10.0,
),
child: TextFormField(
controller: controllerPrice,
maxLines: 1,
inputFormatters: [
new LengthLimitingTextInputFormatter(
5,
),
FilteringTextInputFormatter.digitsOnly,
],
decoration: InputDecoration(
prefixIcon: Icon(Icons.attach_money),
isDense: true,
labelText: 'Price',
helperText: 'Set your Price',
hintText: 'Default Price: 0 \u0024',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
),
);
}
Padding _writeTitle() {
return Padding(
padding: EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 10.0,
),
child: TextFormField(
validator: (value) {
if (value != null) {
if (value.length < 5) {
return 'The title should be at least 5 characters';
}
return null;
};
return null;},
controller: controllerTitle,
maxLines: 1,
inputFormatters: [
new LengthLimitingTextInputFormatter(
50,
),
],
decoration: InputDecoration(
prefixIcon: Icon(
Icons.title,
),
isDense: true,
labelText: 'Title*',
labelStyle: TextStyle(
color: Colors.red,
),
helperText: 'Describe your Product in few words',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(
8.0,
),
),
),
),
);
}
Padding _writeLocation() {
return Padding(
padding: EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 10.0,
),
child: TextFormField(
controller: controllerlocation,
maxLines: 1,
inputFormatters: [
new LengthLimitingTextInputFormatter(
50,
),
],
decoration: InputDecoration(
prefixIcon: Icon(
Icons.location_on,
),
suffixIcon: IconButton(
icon: Icon(Icons.near_me),
onPressed: getLocation,
),
isDense: true,
labelText: 'Location',
helperText: 'Eg: Austin,Texas',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0),
),
),
),
);
}
getLocation() async {
try {
await Permission.location.request();
var status = await Permission.location.status;
if (status.isGranted) {
print('Permission Granted');
Position position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.best);
print(position);
double latitude = position.latitude;
double longitude = position.longitude;
print('latitude: $latitude \n longitude: $longitude');
List<Placemark> placemark = await placemarkFromCoordinates(
latitude,
longitude,
);
setState(() {
print(placemark[0]);
controllerlocation.text =
('${placemark[0].locality},${placemark[0].administrativeArea},${placemark[0].country}')
.toString();
});
} else if (status.isDenied || status.isRestricted) {
print('Permission Denied');
Widget switchButtonType() {
if (Platform.isAndroid) {
return Switch(
value: _switchValue,
onChanged: (value) {
setState(
() {
_switchValue = value;
isReadOnly = _switchValue;
controllerPrice.text = '0';
print(_switchValue);
},
);
},
);
}
return CupertinoSwitch(
value: _switchValue,
onChanged: (value) {
setState(
() {
_switchValue = value;
isReadOnly = _switchValue;
controllerPrice.text = '0';
print(_switchValue);
},
You are filtering items that have isSold set to true but when adding you are adding with isSold set to false. Maybe you should change your filter to .where('isSold', isEqualTo: false)?
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 {}
I am design a screen in which I need to opening a drop down list when user click on textfield till now I am using CupertinoActionSheetAction sheet which is correctly working now I need to replace it with DropdownButton but when I am doing it is not displaying on screen I don't know why.
Here is my code focus on line number 136 (function for CupertinoActionSheetAction is working code) and line 138 where (function for drop not working code) according to me may be it due to build context but I m not sure how to use 'build context' in this context can any one help me out to fix that.
Thanks in advance, And any suggestion for making my code more reusable will be helpful as well :)
import 'dart:ffi';
import 'package:fleet_management/AppContants/Contants.dart';
import 'package:fleet_management/Controllers/NewFuelExpenseController.dart';
import 'package:fleet_management/Models/NewFuelExpenseModel.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class AddFuelView extends StatefulWidget {
const AddFuelView({Key? key}) : super(key: key);
#override
_AddFuelView createState() {
return _AddFuelView();
}
}
// MyTripHistoryView
class _AddFuelView extends State<AddFuelView> {
NewFuelExpenseModel fuelExpense =
NewFuelExpenseController().getNewFuelExpense();
DateTime _selectedDate = DateTime.now();
String dropdownvalue = 'Item 1';
// List of items in our dropdown menu
var items = [
'Item 1',
'Item 2',
'Item 3',
'Item 4',
'Item 5',
];
TextStyle _titleTextStyle = const TextStyle();
TextStyle _valueTextStyle = const TextStyle();
final GlobalKey newFuelExpenseFormField = GlobalKey<FormState>();
final TextEditingController _dateEditingController = TextEditingController();
final TextEditingController _priceTextEditingController =
TextEditingController();
final TextEditingController _gallonsTextEditingController =
TextEditingController();
final TextEditingController _totalTextEditingController =
TextEditingController();
final TextEditingController _odometerTextEditingController =
TextEditingController();
final TextEditingController _fuelTypeTextEditingController =
TextEditingController();
final TextEditingController _vendorTextEditingController =
TextEditingController();
#override
void initState() {
super.initState();
_titleTextStyle =
const TextStyle(fontSize: 16, fontWeight: FontWeight.w600);
_valueTextStyle = const TextStyle(
fontSize: 16, fontWeight: FontWeight.w600, color: Colors.black38);
_dateEditingController.text =
"${_selectedDate.day}-${_selectedDate.month}-${_selectedDate.year}";
}
#override
Widget build(BuildContext context) {
var scaffold = Scaffold(
appBar: AppBar(
title: Text(StringsConstants.newFuelExpense),
backgroundColor: AppColorsConstants.primaryColor,
actions: <Widget>[
FlatButton(
textColor: Colors.white,
onPressed: () {
print("SAVE Button Clicked");
},
child: Text("Save", style: _titleTextStyle),
),
],
),
body: SafeArea(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16),
child: Form(
key: newFuelExpenseFormField,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
showDateRow(context),
addTextFieldInput(
StringsConstants.priceGallon,
"\u{20B9}0.00",
false,
_priceTextEditingController,
TextInputType.datetime,
null,
null),
addTextFieldInput(
StringsConstants.gallons,
"",
false,
_gallonsTextEditingController,
TextInputType.number,
null,
null),
addTextFieldInput(
StringsConstants.total,
"\u{20B9}0.00",
false,
_totalTextEditingController,
TextInputType.number,
null,
null),
addTextFieldInput(
StringsConstants.odometer,
"",
false,
_odometerTextEditingController,
TextInputType.number,
null,
null),
// show action sheet
addTextFieldInput(
StringsConstants.fuelType,
"",
true,
_fuelTypeTextEditingController,
TextInputType.none,
null, () {
// Working. - >>>> HERE <<<<<
showActionSheet(context);
// Not Working >>>> HERE <<<<< Uncomment following function before
// showDropDown();
}),
addTextFieldInput(
StringsConstants.vendor,
"",
false,
_vendorTextEditingController,
TextInputType.text,
null,
null),
const SizedBox(
height: 50,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
ElevatedButton(
onPressed: () {
print("Submit button pressed!");
},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24),
primary: AppColorsConstants.primaryColor,
textStyle:
const TextStyle(fontWeight: FontWeight.bold),
),
child: Text(StringsConstants.submit)),
ElevatedButton(
onPressed: () {
print("Cancel button pressed!");
},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24),
primary: AppColorsConstants.primaryColor,
textStyle:
const TextStyle(fontWeight: FontWeight.bold),
),
child: Text(StringsConstants.cancel))
],
)
],
),
),
),
),
),
);
return scaffold;
}
void showDropDown() {
DropdownButton<String>(
items: <String>['A', 'B', 'C', 'D'].map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (_) {},
);
}
Future<dynamic> showActionSheet(BuildContext context) {
return showCupertinoModalPopup(
context: context,
builder: (BuildContext context) => CupertinoActionSheet(
title: const Text('Choose Options'),
actions: <Widget>[
CupertinoActionSheetAction(
child: const Text('Oil'),
onPressed: () {
_fuelTypeTextEditingController.text = "Oil";
Navigator.pop(context, 'Oil');
},
),
CupertinoActionSheetAction(
child: const Text('Petrol'),
onPressed: () {
_fuelTypeTextEditingController.text = "Petrol";
Navigator.pop(context, 'Petrol');
},
),
CupertinoActionSheetAction(
child: const Text('diesel'),
onPressed: () {
_fuelTypeTextEditingController.text = "diesel";
Navigator.pop(context, 'diesel');
},
)
],
cancelButton: CupertinoActionSheetAction(
child: const Text('Cancel'),
isDefaultAction: true,
onPressed: () {
Navigator.pop(context, 'Cancel');
},
)),
);
}
Container addTextFieldInput(
String title,
String initialValue,
bool isEditable,
TextEditingController textfieldController,
TextInputType keyboardType,
FormFieldValidator<String>? validator,
GestureTapCallback? tabCallback,
) {
return Container(
padding: const EdgeInsets.fromLTRB(0, 16, 0, 8),
child: SizedBox(
child: TextFormField(
onTap: tabCallback,
keyboardType: keyboardType,
cursorHeight: 16,
cursorWidth: 1.4,
readOnly: isEditable,
controller: textfieldController,
validator: validator,
decoration: InputDecoration(
isDense: true,
floatingLabelStyle:
TextStyle(color: AppColorsConstants.primaryColor),
labelText: title,
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: AppColorsConstants.primaryColor, width: 1.5),
),
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black38, width: 1.5),
),
border: const OutlineInputBorder()),
style: const TextStyle(fontSize: 18),
cursorColor: Colors.black38,
showCursor: true,
autofocus: true,
),
),
);
}
Container showDateRow(BuildContext context) {
return Container(
child: TextFormField(
onTap: () => {_selectDate(context)},
cursorHeight: 16,
cursorWidth: 1.4,
readOnly: true,
enableInteractiveSelection: false,
controller: _dateEditingController,
decoration: InputDecoration(
isDense: true,
labelStyle: const TextStyle(color: Colors.orangeAccent),
labelText: StringsConstants.date,
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.orangeAccent, width: 1.5),
),
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.black38, width: 1.5),
),
border: const OutlineInputBorder()),
style: const TextStyle(fontSize: 18),
cursorColor: Colors.black38,
showCursor: true,
autofocus: true,
),
);
}
Future<void> _selectDate(BuildContext context) async {
final DateTime? picked = await showDatePicker(
context: context,
initialDate: _selectedDate,
firstDate: DateTime(1990),
lastDate: DateTime.now());
if (picked != null && picked != _selectedDate) {
setState(() {
_selectedDate = picked;
this._dateEditingController.text =
"${_selectedDate.day}-${_selectedDate.month}-${_selectedDate.year}";
});
}
}
}
For DropDown in flutter you need
an initail value,
a list to be shown just
String selectedvalue='myvalue';
/// be sure you add the variable value in the 0 index of you list other wise it will thrown error or exception..
List<String> myList=[
'myvalue',/// the value is same as variable value
'othe value', ....
];
DropDownButton(
onChanged: (resultValue){
/// you can get selected value from here
},
items: myList.map((e){
retrun DropdownMenuItem(
value: e,
child: Text(e));
}).toList(),
value: selectedvalue,
),
You can use DropdownButtonFormField in place of TextFormField and can make some style related changes per your requirement.
class MyWidget extends StatelessWidget {
String selectedValue = "USA";
List<DropdownMenuItem<String>> get dropdownItems{
List<DropdownMenuItem<String>> menuItems = [
DropdownMenuItem(child: Text("USA"),value: "USA"),
DropdownMenuItem(child: Text("Canada"),value: "Canada"),
DropdownMenuItem(child: Text("Brazil"),value: "Brazil"),
DropdownMenuItem(child: Text("England"),value: "England"),
];
return menuItems;
}
#override
Widget build(BuildContext context) {
return DropdownButtonFormField(
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 2),
borderRadius: BorderRadius.circular(20),
),
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blue, width: 2),
borderRadius: BorderRadius.circular(20),
),
filled: true,
fillColor: Colors.blueAccent,
),
dropdownColor: Colors.blueAccent,
value: selectedValue,
onChanged: (String? newValue) {
selectedValue = newValue!;
},
items: dropdownItems);
}
}
I am trying to create an app that will show the user a generic homepage with products and give them the option to navigate to an account page where, if they are not signed in they will be shown a sign in/sign up page or if they have signed in, they will be shown their profile.
I have managed to get the sign in/sign out part working, but when I sign in and navigate to the profile page, my bottom navigation bar disappears. However, when I navigate to another page and back, it reappears.
Here is my home.dart file which controls navigation for my app:
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
PageController _pageController = PageController();
List<Widget> _screens = [HomePage(), InboxPage(), AccountController()];
int _selectedIndex = 0;
void _onPageChanged(int index) {
setState(() {
_selectedIndex = index;
});
}
void _onItemTapped(int selectedIndex) {
_pageController.jumpToPage(selectedIndex);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: PageView(
controller: _pageController,
children: _screens,
onPageChanged: _onPageChanged,
physics: NeverScrollableScrollPhysics(),
),
bottomNavigationBar: BottomNavigationBar(onTap: _onItemTapped, items: [
BottomNavigationBarItem(
icon: Icon(
Icons.home,
color: _selectedIndex == 0 ? Colors.blueAccent : Colors.grey,
),
title: Text(
'Home',
style: TextStyle(
color: _selectedIndex == 0 ? Colors.blueAccent : Colors.grey,
),
),
),
BottomNavigationBarItem(
icon: Icon(
Icons.email,
color: _selectedIndex == 1 ? Colors.blueAccent : Colors.grey,
),
title: Text(
'Inbox',
style: TextStyle(
color: _selectedIndex == 1 ? Colors.blueAccent : Colors.grey,
),
),
),
BottomNavigationBarItem(
icon: Icon(
Icons.account_circle,
color: _selectedIndex == 2 ? Colors.blueAccent : Colors.grey,
),
title: Text(
'Account',
style: TextStyle(
color: _selectedIndex == 2 ? Colors.blueAccent : Colors.grey,
),
),
),
]),
);
}
}
My accountcontroller.dart code which helps determine whether a user is logged in or not:
class AccountController extends StatelessWidget {
#override
Widget build(BuildContext context) {
final AuthService auth = Provider.of(context).auth;
return StreamBuilder(
stream: auth.onAuthStateChanged,
builder: (context, AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
final bool signedIn = snapshot.hasData;
return signedIn ? ProfileView() : SignUpPage();
}
return CircularProgressIndicator();
});
}
}
My profileview.dart:
class ProfileView extends StatefulWidget {
#override
_ProfileViewState createState() => _ProfileViewState();
}
class _ProfileViewState extends State<ProfileView> {
#override
Widget build(BuildContext context) {
return
Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(80),
child: MainAppBar(
text: 'Account',
)),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Text('Account Page'),
showSignOut(context),
goToHomepage(context),
],
),
),
);
}
}
Widget showSignOut(context) {
return RaisedButton(
child: Text('Sign Out'),
onPressed: () async {
try {
await Provider.of(context).auth.signOut();
Navigator.pushNamed(context, '/homepage');
print('Signed Out');
} catch (e) {
print(e);
}
});
}
Widget goToHomepage(context) {
return RaisedButton(
child: Text('Go to homepage'),
onPressed: () async {
try {
Navigator.pushNamed(context, '/homepage');
} catch (e) {
print(e);
}
});
}
And finally my signup.dart file which contains my sign up/sign in code:
enum AuthFormType { signIn, signUp }
class SignUpPage extends StatefulWidget {
final AuthFormType authFormType;
SignUpPage({Key key, this.authFormType}) : super(key: key);
#override
_SignUpPageState createState() =>
_SignUpPageState(authFormType: this.authFormType);
}
class _SignUpPageState extends State<SignUpPage> {
AuthFormType authFormType;
_SignUpPageState({this.authFormType});
final formKey = GlobalKey<FormState>();
String _firstName,
_lastName,
_email,
_confirmEmail,
_password,
_confirmPassword,
_dateOfBirth;
bool validate() {
final form = formKey.currentState;
form.save();
if (form.validate()) {
form.save();
print('true');
return true;
} else {
print('false');
return false;
}
}
void switchFormState(String state) {
formKey.currentState.reset();
if (state == 'signIn') {
setState(() {
authFormType = AuthFormType.signIn;
});
} else {
setState(() {
authFormType = AuthFormType.signUp;
});
}
}
void submit() async {
final CollectionReference userCollection =
Firestore.instance.collection('UserData');
if (validate()) {
try {
final auth = Provider.of(context).auth;
if (authFormType == AuthFormType.signIn) {
String uid = await auth.signInWithEmailAndPassword(_email, _password);
print("Signed In with ID $uid");
Navigator.of(context).pushReplacementNamed('/home');
} else {
String uid = await auth.createUserWithEmailAndPassword(
_email,
_password,
);
userCollection.document(uid).setData({
'First Name': _firstName,
'Last Name': _lastName,
'Date of Birth': _dateOfBirth
});
print("Signed up with New ID $uid");
Navigator.of(context).pushReplacementNamed('/home');
}
} catch (e) {
print(e);
}
}
}
DateTime selectedDate = DateTime.now();
TextEditingController _date = new TextEditingController();
Future<Null> _selectDate(BuildContext context) async {
DateFormat formatter =
DateFormat('dd/MM/yyyy'); //specifies day/month/year format
final DateTime picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(1901, 1),
builder: (BuildContext context, Widget child) {
return Theme(
data: ThemeData.light().copyWith(
colorScheme: ColorScheme.light(
primary: kPrimaryColor,
onPrimary: Colors.black,),
buttonTheme: ButtonThemeData(
colorScheme: Theme.of(context)
.colorScheme
.copyWith(primary: Colors.black),
),
),
child: child,
);
},
lastDate: DateTime(2100));
if (picked != null && picked != selectedDate)
setState(() {
selectedDate = picked;
_date.value = TextEditingValue(
text: formatter.format(
picked)); //Use formatter to format selected date and assign to text field
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(80),
child: MainAppBar(
text: buildAppBarText(),
)),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Center(
child: Container(
child: Column(
children: <Widget>[
Align(
child: Text(buildTitleText(), style: AppBarTextStyle),
),
Container(
padding: EdgeInsets.only(top: 10),
),
Padding(
padding: const EdgeInsets.all(20.0),
child: Form(
key: formKey,
child: Column(
children: buildInputs() + buildSwitchText(),
)),
),
],
),
),
),
),
));
}
buildHeaderText() {
String _headerText;
if (authFormType == AuthFormType.signUp) {
_headerText = "Don't have an account?";
} else {
_headerText = "Already have an account?";
}
return _headerText;
}
List<Widget> buildInputs() {
List<Widget> textFields = [];
DateFormat dateFormat = DateFormat("yyyy-MM-dd HH:mm:ss");
if (authFormType == AuthFormType.signIn) {
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Email'),
validator: SignInEmailValidator.validate,
onSaved: (value) => _email = value.trim()));
textFields.add(SizedBox(
height: 15,
));
textFields.add(
TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Password'),
obscureText: true,
validator: SignInPasswordValidator.validate,
onSaved: (value) => _password = value.trim(),
),
);
} else {
textFields.clear();
//if we're in the sign up state, add name
// add email & password
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('First Name'),
validator: NameValidator.validate,
onSaved: (value) => _firstName = value,
));
textFields.add(SizedBox(
height: 15,
));
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Last Name'),
onSaved: (value) => _lastName = value,
validator: NameValidator.validate,
));
textFields.add(SizedBox(
height: 15,
));
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Email Address'),
onSaved: (value) => _email = value.trim(),
validator: SignInEmailValidator.validate,
));
textFields.add(SizedBox(
height: 15,
));
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Confirm Email Address'),
onSaved: (value) => _confirmEmail = value,
validator: (confirmation) {
return confirmation == _email
? null
: "Confirm Email Address should match email address";
},
));
textFields.add(SizedBox(
height: 15,
));
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Password'),
obscureText: true,
onSaved: (value) => _password = value,
));
textFields.add(SizedBox(
height: 15,
));
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Confirm Password'),
onSaved: (value) => _confirmPassword = value,
validator: (confirmation) {
return confirmation == _password
? null
: "Confirm Password should match password";
}));
textFields.add(SizedBox(
height: 15,
));
textFields.add(GestureDetector(
onTap: () => _selectDate(context),
child: AbsorbPointer(
child: TextFormField(
style: TextStyle(fontSize: 12.0),
controller: _date,
keyboardType: TextInputType.datetime,
decoration: InputDecoration(
isDense: true,
fillColor: Colors.white,
hintText: 'Date of Birth',
filled: true,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(width: 0.0),
),
contentPadding:
const EdgeInsets.only(left: 14.0, bottom: 10.0, top: 10.0),
),
onSaved: (value) => _dateOfBirth = value,
),
),
));
textFields.add(SizedBox(
height: 15,
));
}
return textFields;
}
List<Widget> buildSwitchText() {
String _switchButtonTextPart1, _switchButtonTextPart2, _newFormState;
if (authFormType == AuthFormType.signIn) {
_switchButtonTextPart1 = "Haven't got an account? ";
_switchButtonTextPart2 = 'Sign Up';
_newFormState = 'signUp';
} else {
_switchButtonTextPart1 = 'Already have an account? ';
_switchButtonTextPart2 = 'Sign In';
_newFormState = 'signIn';
}
return [
SizedBox(height: 5.0),
Container(
width: MediaQuery.of(context).size.height * 0.7,
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0),
),
color: kPrimaryColor,
textColor: Colors.black,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
buildTitleText(),
style: TextStyle(fontFamily: FontNameDefault, fontSize: 15.0),
),
),
onPressed: submit),
),
SizedBox(
height: 5.0,
),
RichText(
text: TextSpan(
style: TextStyle(
fontFamily: FontNameDefault,
color: Colors.black,
fontSize: 12.0,
),
children: <TextSpan>[
TextSpan(text: _switchButtonTextPart1),
TextSpan(
text: _switchButtonTextPart2,
style: TextStyle(
decoration: TextDecoration.underline,
color: Colors.black,
fontSize: 12.0),
recognizer: TapGestureRecognizer()
..onTap = () {
switchFormState(_newFormState);
})
]),
),
];
}
String buildAppBarText() {
String _switchAppBarHeader;
if (authFormType == AuthFormType.signIn) {
_switchAppBarHeader = "Already have an account?";
} else {
_switchAppBarHeader = "Don't have an account?";
}
return _switchAppBarHeader;
}
String buildTitleText() {
String _switchTextHeader;
if (authFormType == AuthFormType.signIn) {
_switchTextHeader = "Sign In";
} else {
_switchTextHeader = "Sign Up";
}
return _switchTextHeader;
}
}
InputDecoration buildSignUpInputDecoration(String hint) {
return InputDecoration(
isDense: true,
fillColor: Colors.white,
hintText: hint,
filled: true,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(width: 0.0),
),
contentPadding: const EdgeInsets.only(left: 14.0, bottom: 10.0, top: 10.0),
);
}
Any ideas?
The HomePage(), InboxPage() and AccountController() are in your home-widget, which contains the bottomNavigationBar.
Your profile and signup pages are different pages with its own scaffold.
You have to create one central "index" widget wich holds every sub-page and the navigationbar.