Я создал модели для данных из конечной точки API и использовал управление состоянием mobx для проекта. Чтобы создать контакт, у меня возникла ошибка, которая не позволяет мне успешно создать новый контакт.
class NewContact extends StatefulWidget {
NewContact({Key key}) : super(key: key);
@override
_NewContactState createState() {
return _NewContactState();
}
}
class _NewContactState extends State<NewContact> {
bool visibility = false;
ErrorPage _errorPage;
ContactStore contactStore;
@override
void initState() {
super.initState();
_errorPage = ErrorPage();
}
@override
void dispose() {
contactStore.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final data = MediaQuery.of(context);
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: true,
iconTheme: IconThemeData(color: Colors.black),
backgroundColor: Colors.white,
elevation: 0.0,
title: Text(
'New Contact',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
color: Color.fromRGBO(35, 36, 44, 1)),
),
),
body: Provider(
create: (context) => ContactStore(),
dispose: (context, verifyStore) => verifyStore.dispose(),
child: Consumer<ContactStore>(
builder: (context, contactStore, _) {
if (contactStore.isNotInitialized) {
contactStore.initialize(context);
}
return Container(
height: data.size.height,
width: data.size.width,
margin: EdgeInsets.symmetric(horizontal: 22),
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
return SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
// height: data.size.height / 2,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(
height: MediaQuery.of(context).size.height * 0.08,
),
Text(
"Step 1/2",
style: TextStyle(
color: Colors.black,
//color: Color.fromRGBO(255, 255, 255, 1),
fontSize: 14.0,
fontWeight: FontWeight.w500),
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.02,
),
Text(
"Personal Details",
style: TextStyle(
//color: Colors.black,
color: Color.fromRGBO(35, 36, 44, 1),
fontSize: 20.0,
fontWeight: FontWeight.w500),
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.06,
),
Container(
height: 60,
width: MediaQuery.of(context).size.width,
child: Stack(
children: <Widget>[
Text(
"Full Name",
style: TextStyle(
color: Colors.black,
//color: Color.fromRGBO(128, 132, 162, 1),
fontSize: 14.0,
fontWeight: FontWeight.w500),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: Observer(
name: 'description',
builder: (_) => TextFormField(
controller: contactStore.contactNameController,
keyboardType: TextInputType.text,
decoration: InputDecoration(
errorText: contactStore
.contactFormErrorStore.description,
hintText: "Aliyu Shamsuddeen"),
),
),
),
],
),
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.03,
),
Container(
height: 60,
width: MediaQuery.of(context).size.width,
child: Stack(
children: <Widget>[
Text(
"Email Address",
style: TextStyle(
color: Colors.black,
//color: Color.fromRGBO(128, 132, 162, 1),
fontSize: 14.0,
fontWeight: FontWeight.w500),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: Observer(
name: 'contactEmail',
builder: (_) => TextFormField(
controller: contactStore.emailController,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
errorText: contactStore
.contactFormErrorStore.contactEmail,
hintText: "email@example.com"),
),
),
),
],
),
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.03,
),
Container(
height: 60,
width: MediaQuery.of(context).size.width,
child: Stack(
children: <Widget>[
Text(
"Mobile Number",
style: TextStyle(
color: Colors.black,
//color: Color.fromRGBO(128, 132, 162, 1),
fontSize: 14.0,
fontWeight: FontWeight.w500),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: Observer(
name: 'contactPhone',
builder: (_) => TextFormField(
controller: contactStore.numberController,
keyboardType: TextInputType.number,
decoration: InputDecoration(
errorText: contactStore
.contactFormErrorStore.contactPhone,
hintText: "0803123456789"),
),
),
),
],
),
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.03,
),
Container(
height: 60,
width: MediaQuery.of(context).size.width,
child: Stack(
children: <Widget>[
Text(
"Address",
style: TextStyle(
color: Colors.black,
//color: Color.fromRGBO(128, 132, 162, 1),
fontSize: 14.0,
fontWeight: FontWeight.w500),
),
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: Observer(
name: 'contactAddress',
builder: (_) => TextFormField(
controller: contactStore.contactAddressController ,
keyboardType: TextInputType.text,
decoration: InputDecoration(
errorText: contactStore
.contactFormErrorStore.contactAddress,
hintText:
"No.2 Galadimawa Estate Minna."),
),
),
),
],
),
),
SizedBox(
height: MediaQuery.of(context).size.height * 0.06,
),
Container(
height: 48.0,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16.0)),
child: RaisedButton(
elevation: 0.0,
color: Color.fromRGBO(68, 74, 213, 1),
onPressed: () {
// Navigator.of(context)
// .popAndPushNamed('/contactDetails');
contactStore.saveContact();
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'Continue',
style: new TextStyle(
color:
Color.fromRGBO(235, 234, 250, 1),
fontSize: 14.0,
fontWeight: FontWeight.w500),
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Icon(
Icons.arrow_forward,
color: Colors.white,
size: 16.0,
),
),
],
),
),
),
],
),
),
],
),
);
},
),
);
},
),
));
}
}
Это содержимое хранилища для модуля контактов для создания и отображения уже созданных контактов в качестве организации или как физическое лицо.
part 'contact_store.g.dart';
class ContactStore = _ContactStore with _$ContactStore;
// The store-class
abstract class _ContactStore with Store {
final Validation _validate = new Validation();
final ErrorStore errorStore = new ErrorStore();
final ContactFormErrorStore contactFormErrorStore =
new ContactFormErrorStore();
List bankList = [
'Access Bank',
'Citibank',
'Diamond Bank',
'Ecobank Nigeria',
'Fidelity Bank Nigeria',
'First Bank of Nigeria',
'First City Monument Bank',
'Guaranty Trust Bank',
'Heritage Bank Plc',
'Jaiz Bank',
'Keystone Bank Limited',
'Providus Bank Plc',
'Polaris Bank',
'Stanbic IBTC Bank Nigeria Limited',
'Standard Chartered Bank',
'Sterling Bank',
'SunTrust Bank Nigeria Limited',
'Union Bank of Nigeria',
'United Bank for Africa',
'Unity Bank Plc',
'Wema Bank',
'Zenith Bank'
];
List<DropdownMenuItem<String>> dropDownMenuItems;
List<DropdownMenuItem<String>> getDropDownMenuItems() {
List<DropdownMenuItem<String>> items = new List();
for (String user in bankList) {
items.add(new DropdownMenuItem(value: user, child: new Text(user)));
}
return items;
}
GlobalStore globalStore;
List<ReactionDisposer> _disposers;
List<Contact> contactListData;
int id;
final contactNameController = TextEditingController();
final emailController = TextEditingController();
final numberController = TextEditingController();
final contactAddressController = TextEditingController();
final accountNumberController = TextEditingController();
final accountNameController = TextEditingController();
final bankBranchController = TextEditingController();
final contactPersonController = TextEditingController();
@observable
bool visibility = false;
@observable
int categoryId;
@observable
var getContactListState = Status.none;
@observable
bool isFiltering = false;
@observable
String searchText = '';
@observable
ObservableFuture getContactListCheck = ObservableFuture.value(null);
@computed
bool get isGetContactListPending =>
getContactListCheck.status == FutureStatus.pending;
var apiCallState = Status.none;
@observable
BuildContext context;
@observable
String description = '';
@observable
String contactEmail = '';
@observable
String contactPhone = '';
@observable
String contactAddress = '';
@observable
String accountName = '';
@observable
String accountNo = '';
@observable
String bankAddress = '';
@observable
String bankCode = '';
@observable
String currentBankType;
@observable
List<BankItem> bankItemList;
// @observable
// String contactPerson = '';
@action
void changedDropDownItem(String selectedBankType) {
currentBankType = selectedBankType;
}
@computed
bool get isNotInitialized => context == null;
@computed
bool get canNavigate => apiCallState != Status.failed;
@computed
bool get canCreateContact =>
!contactFormErrorStore.hasError &&
description.isNotEmpty &&
contactEmail.isNotEmpty &&
contactPhone.isNotEmpty &&
contactAddress.isNotEmpty &&
accountName.isNotEmpty &&
accountNo.isNotEmpty &&
bankAddress.isNotEmpty &&
bankCode.isNotEmpty;
@action
void setContext(BuildContext val) {
context = val;
}
@action
void setVariables(BuildContext context) {
globalStore = Provider.of<GlobalStore>(context);
}
@action
void setName(String value) {
description = value;
}
@action
void setEmail(String value) {
contactEmail = value;
}
@action
void setNumber(String value) {
contactPhone = value;
}
@action
void setAddress(String value) {
contactAddress = value;
}
@action
void setAcctName(String value) {
accountName = value;
}
@action
void setAcctNumber(String value) {
accountNo = value;
}
@action
void setBankAddress(String value) {
bankAddress = value;
}
@action
void setBankCode(String value) {
bankCode = value;
}
@action
void setCurrentBankType() {
currentBankType = dropDownMenuItems[0].value;
}
@action
void validateFields() {
String result;
bool result1;
result = _validate.validateFullName(description);
contactFormErrorStore.description = result;
result = _validate.validateEmail(contactEmail);
contactFormErrorStore.contactEmail = result;
result1 = _validate.isValidPhoneNumber(contactPhone);
contactFormErrorStore.contactPhone = result1 as String;
result = _validate.validateContactAddress(contactAddress);
contactFormErrorStore.contactAddress = result;
result = _validate.validateAccountName(accountName);
contactFormErrorStore.accountName = result;
result1 = _validate.validateAccountNumber(accountNo);
contactFormErrorStore.accountNo = result1 as String;
contactFormErrorStore.bankAddress = result;
result = _validate.validateBankAddress(bankAddress);
}
void saveContact() async {
validateFields();
List<Map> contactBanksList = List<Map>();
// List<Map> bankItems = List<Map>();
for (BankItem bankItem in bankItemList) {
contactBanksList.add(bankItem.toJson());
}
if (canCreateContact) {
apiCallState = Status.none;
ShowProgressIndicatorDialog(context: context);
//await checkEmailExist();
if (canNavigate && canCreateContact) {
try {
AddContact result = await ContactDataSource().addContact(
requestPayload: AddContactRequest(
//category
description: description,
contactAddress: contactAddress,
contactPhone: contactPhone,
contactEmail: contactEmail,
contactBanksList: contactBanksList
//category: category,
)
.toJson(),
);
Navigator.of(context).pop();
if (result.message == SUCCESS) {
Navigator.of(context).pushNamed(
'/contactDetails',
);
} else {
ShowFlushBar(context: context, message: OPERATION_UNSUCESSFUL);
}
} on CustomException catch (e) {
Navigator.of(context).pop();
errorStore.errorMessage = e.msg;
ShowFlushBar(context: context, message: errorStore.errorMessage);
}
}
// else {
// Navigator.of(context).pop();
// if (apiCallState == Status.failed) {
// ShowFlushBar(context: context, message: errorStore.errorMessage);
// }
// }
}
}
void setListeners() {
contactNameController.addListener(() {
setName(contactNameController.text);
});
emailController.addListener(() {
setEmail(emailController.text);
});
numberController.addListener(() {
setNumber(numberController.text);
});
contactAddressController.addListener(() {
setAddress(contactAddressController.text);
});
accountNumberController.addListener(() {
setAcctNumber(accountNumberController.text);
});
accountNameController.addListener(() {
setAcctName(accountNameController.text);
});
bankBranchController.addListener(() {
setBankAddress(bankBranchController.text);
});
contactPersonController.addListener(() {
setBankCode(contactPersonController.text);
});
}
@action
Future getContacts() async {
getContactListState = Status.loading;
try {
List<Contact> result = await ContactDataSource().contactList(
userId: globalStore.loginData.userID,
basicAuth: globalStore.basicAuth);
if (searchText == "") {
contactListData = result;
} else {
List<Contact> newContactListData = List<Contact>();
for (Contact contact in result) {
if (contact.description
.toLowerCase()
.contains(searchText.toLowerCase()) ||
contact.contactEmail
.toLowerCase()
.contains(searchText.toLowerCase())) {
newContactListData.add(contact);
}
}
contactListData = newContactListData;
}
getContactListState = Status.none;
} on CustomException catch (e) {
getContactListState = Status.failed;
errorStore.errorMessage = e.msg;
}
}
@action
Future getContactList(String searchText) async {
getContactListCheck = ObservableFuture(getContacts());
}
@action
Future deleteContact(int index) async {
ShowProgressIndicatorDialog(context: context);
try {
DeleteContact result = await ContactDataSource().deleteContact(
id: contactListData[index].id, basicAuth: globalStore.basicAuth);
Navigator.of(context).pop();
if (result.message == SUCCESS) {
await getContactList("");
ShowToast(
msg: ITEM_DELETED,
backgroundColor: main,
);
} else {
Navigator.of(context).pop();
ShowFlushBar(context: context, message: DELETE_ERROR_MSG);
}
} on CustomException catch (e) {
Navigator.of(context).pop();
errorStore.errorMessage = e.msg;
ShowFlushBar(context: context, message: errorStore.errorMessage);
}
}
@override
void dispose() {
for (final d in _disposers) {
d();
}
}
void initialize(BuildContext val) {
_disposers = [
reaction((_) => context, setVariables),
reaction((_) => searchText, getContactList)
];
setContext(val);
getContactList("");
}
}
class ContactFormErrorStore = _ContactFormErrorStore
with _$ContactFormErrorStore;
abstract class _ContactFormErrorStore with Store {
@observable
String description = '';
@observable
String contactEmail = '';
@observable
String contactPhone = '';
@observable
String contactAddress = '';
@observable
String accountName = '';
@observable
String accountNo = '';
@observable
String bankAddress = '';
@observable
String bankCode = '';
@computed
bool get hasError =>
description != null ||
contactEmail != null ||
contactPhone != null ||
contactAddress != null ||
accountName != null ||
accountNo != null ||
bankAddress != null ||
bankCode != null;
}