Packages And offers..

merge-update-with-lab-changes
Zohaib Iqbal Kambrani 5 years ago
parent f410ce20ca
commit 6f2c947687

@ -1,3 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="312.602" height="292.689" viewBox="0 0 312.602 292.689"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="312.602" height="292.689" viewBox="0 0 312.602 292.689">
<defs> <defs>
<radialGradient id="radial-gradient" cx="0.236" cy="0.508" r="0.361" gradientTransform="matrix(4.725, 0.181, -0.871, 0.983, -15.148, -0.89)" gradientUnits="objectBoundingBox"> <radialGradient id="radial-gradient" cx="0.236" cy="0.508" r="0.361" gradientTransform="matrix(4.725, 0.181, -0.871, 0.983, -15.148, -0.89)" gradientUnits="objectBoundingBox">

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 19 KiB

@ -11,8 +11,9 @@ const MAX_SMALL_SCREEN = 660;
const EXA_CART_API_BASE_URL = 'http://10.200.101.75:9000'; const EXA_CART_API_BASE_URL = 'http://10.200.101.75:9000';
const PACKAGES_CATEGORIES = '/api/categories'; const PACKAGES_CATEGORIES = '/api/categories';
const PACKAGES_PRODUCTS = '/api/products'; const PACKAGES_PRODUCTS = '/api/products';
const PACKAGES_SHOPPING_CART = '/api/shopping_cart_items';
const PACKAGES_CUSTOMER = '/api/customers'; const PACKAGES_CUSTOMER = '/api/customers';
const PACKAGES_SHOPPING_CART = '/api/shopping_cart_items';
const PACKAGES_ORDERS = '/api/orders';
const BASE_URL = 'https://uat.hmgwebservices.com/'; const BASE_URL = 'https://uat.hmgwebservices.com/';
// const BASE_URL = 'https://hmgwebservices.com/'; // const BASE_URL = 'https://hmgwebservices.com/';

@ -0,0 +1,34 @@
enum PaymentOptions {
VISA,
MASTERCARD,
MADA,
INSTALLMENT,
APPLEPAY
}
extension PaymentOptions_ on PaymentOptions{
String value(){
switch(this){
case PaymentOptions.VISA:
return "VISA";
break;
case PaymentOptions.MASTERCARD:
return "MASTERCARD";
break;
case PaymentOptions.MADA:
return "MADA";
break;
case PaymentOptions.INSTALLMENT:
return "INSTALLMENT";
break;
case PaymentOptions.APPLEPAY:
return "APPLEPAY";
break;
}
return null;
}
}

@ -0,0 +1,7 @@
class ResponseModel<T>{
final bool status;
final String error;
final T data;
ResponseModel({this.status, this.data, this.error});
}

@ -1,7 +1,7 @@
import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesResponseModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesResponseModel.dart';
class CartProductResponseModel { class PackagesCartItemsResponseModel {
int _quantity; int _quantity;
set quantity(int value) { set quantity(int value) {
@ -19,7 +19,7 @@ class CartProductResponseModel {
PackagesResponseModel get product => _product; PackagesResponseModel get product => _product;
int get id => _id; int get id => _id;
CartProductResponseModel({ PackagesCartItemsResponseModel({
int quantity, int quantity,
String shoppingCartType, String shoppingCartType,
int productId, int productId,
@ -32,7 +32,7 @@ class CartProductResponseModel {
_id = id; _id = id;
} }
CartProductResponseModel.fromJson(dynamic json) { PackagesCartItemsResponseModel.fromJson(dynamic json) {
_quantity = json["quantity"]; _quantity = json["quantity"];
_shoppingCartType = json["shopping_cart_type"]; _shoppingCartType = json["shopping_cart_type"];
_productId = json["product_id"]; _productId = json["product_id"];

@ -1,8 +1,38 @@
import 'PackagesCartItemsResponseModel.dart';
/// shopping_cart_items : []
/// billing_address : null
/// shipping_address : null
/// addresses : [{"first_name":null,"last_name":null,"email":"a2zzuhaib@gmil.com","company":null,"country_id":null,"country":null,"state_province_id":null,"city":null,"address1":null,"address2":null,"zip_postal_code":null,"phone_number":"0500409598","fax_number":null,"customer_attributes":null,"created_on_utc":"2021-03-11T09:40:23.8091261Z","province":null,"id":0}]
/// customer_guid : "1367e5c7-be3b-43cc-ad81-ff1fc8d3b130"
/// username : null
/// email : "a2zzuhaib@gmil.com"
/// first_name : null
/// last_name : null
/// language_id : null
/// date_of_birth : null
/// gender : null
/// admin_comment : null
/// is_tax_exempt : false
/// has_shopping_cart_items : false
/// active : true
/// deleted : false
/// is_system_account : false
/// system_name : null
/// last_ip_address : null
/// created_on_utc : "2021-03-11T09:40:23.7535859Z"
/// last_login_date_utc : null
/// last_activity_date_utc : "2021-03-11T09:40:23.7535892Z"
/// registered_in_store_id : 0
/// subscribed_to_newsletter : false
/// role_ids : []
/// id : 76823
class PackagesCustomerResponseModel { class PackagesCustomerResponseModel {
List<dynamic> _shoppingCartItems; List<PackagesCartItemsResponseModel> _shoppingCartItems;
dynamic _billingAddress; dynamic _billingAddress;
dynamic _shippingAddress; dynamic _shippingAddress;
List<dynamic> _addresses; List<Addresses> _addresses;
String _customerGuid; String _customerGuid;
dynamic _username; dynamic _username;
String _email; String _email;
@ -24,13 +54,13 @@ class PackagesCustomerResponseModel {
String _lastActivityDateUtc; String _lastActivityDateUtc;
int _registeredInStoreId; int _registeredInStoreId;
bool _subscribedToNewsletter; bool _subscribedToNewsletter;
List<dynamic> _roleIds; List<int> _roleIds;
int _id; int _id;
List<dynamic> get shoppingCartItems => _shoppingCartItems; List<dynamic> get shoppingCartItems => _shoppingCartItems;
dynamic get billingAddress => _billingAddress; dynamic get billingAddress => _billingAddress;
dynamic get shippingAddress => _shippingAddress; dynamic get shippingAddress => _shippingAddress;
List<dynamic> get addresses => _addresses; List<Addresses> get addresses => _addresses;
String get customerGuid => _customerGuid; String get customerGuid => _customerGuid;
dynamic get username => _username; dynamic get username => _username;
String get email => _email; String get email => _email;
@ -59,7 +89,7 @@ class PackagesCustomerResponseModel {
List<dynamic> shoppingCartItems, List<dynamic> shoppingCartItems,
dynamic billingAddress, dynamic billingAddress,
dynamic shippingAddress, dynamic shippingAddress,
List<dynamic> addresses, List<Addresses> addresses,
String customerGuid, String customerGuid,
dynamic username, dynamic username,
String email, String email,
@ -115,6 +145,12 @@ class PackagesCustomerResponseModel {
PackagesCustomerResponseModel.fromJson(dynamic json) { PackagesCustomerResponseModel.fromJson(dynamic json) {
_billingAddress = json["billing_address"]; _billingAddress = json["billing_address"];
_shippingAddress = json["shipping_address"]; _shippingAddress = json["shipping_address"];
if (json["addresses"] != null) {
_addresses = [];
json["addresses"].forEach((v) {
_addresses.add(Addresses.fromJson(v));
});
}
_customerGuid = json["customer_guid"]; _customerGuid = json["customer_guid"];
_username = json["username"]; _username = json["username"];
_email = json["email"]; _email = json["email"];
@ -136,26 +172,22 @@ class PackagesCustomerResponseModel {
_lastActivityDateUtc = json["last_activity_date_utc"]; _lastActivityDateUtc = json["last_activity_date_utc"];
_registeredInStoreId = json["registered_in_store_id"]; _registeredInStoreId = json["registered_in_store_id"];
_subscribedToNewsletter = json["subscribed_to_newsletter"]; _subscribedToNewsletter = json["subscribed_to_newsletter"];
_id = json["id"];
// if (json["role_ids"] != null) { if (json["role_ids"] != null) {
// _roleIds = []; _roleIds = [];
// json["role_ids"].forEach((v) { json["role_ids"].forEach((v) {
// _roleIds.add(dynamic.fromJson(v)); _roleIds.add(v);
// }); });
// } }
// if (json["addresses"] != null) {
// _addresses = []; if (json["shopping_cart_items"] != null) {
// json["addresses"].forEach((v) { _shoppingCartItems = [];
// _addresses.add(dynamic.fromJson(v)); json["shopping_cart_items"].forEach((v) {
// }); _shoppingCartItems.add(PackagesCartItemsResponseModel.fromJson(v));
// } });
// if (json["shopping_cart_items"] != null) { }
// _shoppingCartItems = [];
// json["shopping_cart_items"].forEach((v) { _id = json["id"];
// _shoppingCartItems.add(dynamic.fromJson(v));
// });
// }
} }
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
@ -190,10 +222,146 @@ class PackagesCustomerResponseModel {
map["registered_in_store_id"] = _registeredInStoreId; map["registered_in_store_id"] = _registeredInStoreId;
map["subscribed_to_newsletter"] = _subscribedToNewsletter; map["subscribed_to_newsletter"] = _subscribedToNewsletter;
if (_roleIds != null) { if (_roleIds != null) {
map["role_ids"] = _roleIds.map((v) => v.toJson()).toList(); map["role_ids"] = _roleIds.map((v) => v).toList();
} }
map["id"] = _id; map["id"] = _id;
return map; return map;
} }
} }
/// first_name : null
/// last_name : null
/// email : "a2zzuhaib@gmil.com"
/// company : null
/// country_id : null
/// country : null
/// state_province_id : null
/// city : null
/// address1 : null
/// address2 : null
/// zip_postal_code : null
/// phone_number : "0500409598"
/// fax_number : null
/// customer_attributes : null
/// created_on_utc : "2021-03-11T09:40:23.8091261Z"
/// province : null
/// id : 0
class Addresses {
dynamic _firstName;
dynamic _lastName;
String _email;
dynamic _company;
dynamic _countryId;
dynamic _country;
dynamic _stateProvinceId;
dynamic _city;
dynamic _address1;
dynamic _address2;
dynamic _zipPostalCode;
String _phoneNumber;
dynamic _faxNumber;
dynamic _customerAttributes;
String _createdOnUtc;
dynamic _province;
int _id;
dynamic get firstName => _firstName;
dynamic get lastName => _lastName;
String get email => _email;
dynamic get company => _company;
dynamic get countryId => _countryId;
dynamic get country => _country;
dynamic get stateProvinceId => _stateProvinceId;
dynamic get city => _city;
dynamic get address1 => _address1;
dynamic get address2 => _address2;
dynamic get zipPostalCode => _zipPostalCode;
String get phoneNumber => _phoneNumber;
dynamic get faxNumber => _faxNumber;
dynamic get customerAttributes => _customerAttributes;
String get createdOnUtc => _createdOnUtc;
dynamic get province => _province;
int get id => _id;
Addresses({
dynamic firstName,
dynamic lastName,
String email,
dynamic company,
dynamic countryId,
dynamic country,
dynamic stateProvinceId,
dynamic city,
dynamic address1,
dynamic address2,
dynamic zipPostalCode,
String phoneNumber,
dynamic faxNumber,
dynamic customerAttributes,
String createdOnUtc,
dynamic province,
int id}){
_firstName = firstName;
_lastName = lastName;
_email = email;
_company = company;
_countryId = countryId;
_country = country;
_stateProvinceId = stateProvinceId;
_city = city;
_address1 = address1;
_address2 = address2;
_zipPostalCode = zipPostalCode;
_phoneNumber = phoneNumber;
_faxNumber = faxNumber;
_customerAttributes = customerAttributes;
_createdOnUtc = createdOnUtc;
_province = province;
_id = id;
}
Addresses.fromJson(dynamic json) {
_firstName = json["first_name"];
_lastName = json["last_name"];
_email = json["email"];
_company = json["company"];
_countryId = json["country_id"];
_country = json["country"];
_stateProvinceId = json["state_province_id"];
_city = json["city"];
_address1 = json["address1"];
_address2 = json["address2"];
_zipPostalCode = json["zip_postal_code"];
_phoneNumber = json["phone_number"];
_faxNumber = json["fax_number"];
_customerAttributes = json["customer_attributes"];
_createdOnUtc = json["created_on_utc"];
_province = json["province"];
_id = json["id"];
}
Map<String, dynamic> toJson() {
var map = <String, dynamic>{};
map["first_name"] = _firstName;
map["last_name"] = _lastName;
map["email"] = _email;
map["company"] = _company;
map["country_id"] = _countryId;
map["country"] = _country;
map["state_province_id"] = _stateProvinceId;
map["city"] = _city;
map["address1"] = _address1;
map["address2"] = _address2;
map["zip_postal_code"] = _zipPostalCode;
map["phone_number"] = _phoneNumber;
map["fax_number"] = _faxNumber;
map["customer_attributes"] = _customerAttributes;
map["created_on_utc"] = _createdOnUtc;
map["province"] = _province;
map["id"] = _id;
return map;
}
}

@ -0,0 +1,323 @@
import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesCustomerResponseModel.dart';
import 'PackagesCartItemsResponseModel.dart';
class PackagesOrderResponseModel {
String _customOrderNumber;
int _storeId;
dynamic _pickUpInStore;
String _paymentMethodSystemName;
String _customerCurrencyCode;
double _currencyRate;
int _customerTaxDisplayTypeId;
dynamic _vatNumber;
double _orderSubtotalInclTax;
double _orderSubtotalExclTax;
double _orderSubTotalDiscountInclTax;
double _orderSubTotalDiscountExclTax;
double _orderShippingInclTax;
double _orderShippingExclTax;
double _paymentMethodAdditionalFeeInclTax;
double _paymentMethodAdditionalFeeExclTax;
String _taxRates;
double _orderTax;
double _orderDiscount;
double _orderTotal;
double _refundedAmount;
dynamic _rewardPointsWereAdded;
String _checkoutAttributeDescription;
int _customerLanguageId;
int _affiliateId;
String _customerIp;
dynamic _authorizationTransactionId;
dynamic _authorizationTransactionCode;
dynamic _authorizationTransactionResult;
dynamic _captureTransactionId;
dynamic _captureTransactionResult;
dynamic _subscriptionTransactionId;
dynamic _paidDateUtc;
dynamic _shippingMethod;
dynamic _shippingRateComputationMethodSystemName;
String _customValuesXml;
dynamic _paymentOption;
bool _deleted;
String _createdOnUtc;
PackagesCustomerResponseModel _customer;
int _customerId;
dynamic _billingAddress;
dynamic _shippingAddress;
List<PackagesCartItemsResponseModel> _orderItems;
String _orderStatus;
String _paymentStatus;
String _shippingStatus;
String _customerTaxDisplayType;
int _id;
String get customOrderNumber => _customOrderNumber;
int get storeId => _storeId;
dynamic get pickUpInStore => _pickUpInStore;
String get paymentMethodSystemName => _paymentMethodSystemName;
String get customerCurrencyCode => _customerCurrencyCode;
double get currencyRate => _currencyRate;
int get customerTaxDisplayTypeId => _customerTaxDisplayTypeId;
dynamic get vatNumber => _vatNumber;
double get orderSubtotalInclTax => _orderSubtotalInclTax;
double get orderSubtotalExclTax => _orderSubtotalExclTax;
double get orderSubTotalDiscountInclTax => _orderSubTotalDiscountInclTax;
double get orderSubTotalDiscountExclTax => _orderSubTotalDiscountExclTax;
double get orderShippingInclTax => _orderShippingInclTax;
double get orderShippingExclTax => _orderShippingExclTax;
double get paymentMethodAdditionalFeeInclTax => _paymentMethodAdditionalFeeInclTax;
double get paymentMethodAdditionalFeeExclTax => _paymentMethodAdditionalFeeExclTax;
String get taxRates => _taxRates;
double get orderTax => _orderTax;
double get orderDiscount => _orderDiscount;
double get orderTotal => _orderTotal;
double get refundedAmount => _refundedAmount;
dynamic get rewardPointsWereAdded => _rewardPointsWereAdded;
String get checkoutAttributeDescription => _checkoutAttributeDescription;
int get customerLanguageId => _customerLanguageId;
int get affiliateId => _affiliateId;
String get customerIp => _customerIp;
dynamic get authorizationTransactionId => _authorizationTransactionId;
dynamic get authorizationTransactionCode => _authorizationTransactionCode;
dynamic get authorizationTransactionResult => _authorizationTransactionResult;
dynamic get captureTransactionId => _captureTransactionId;
dynamic get captureTransactionResult => _captureTransactionResult;
dynamic get subscriptionTransactionId => _subscriptionTransactionId;
dynamic get paidDateUtc => _paidDateUtc;
dynamic get shippingMethod => _shippingMethod;
dynamic get shippingRateComputationMethodSystemName => _shippingRateComputationMethodSystemName;
String get customValuesXml => _customValuesXml;
dynamic get paymentOption => _paymentOption;
bool get deleted => _deleted;
String get createdOnUtc => _createdOnUtc;
PackagesCustomerResponseModel get customer => _customer;
int get customerId => _customerId;
dynamic get billingAddress => _billingAddress;
dynamic get shippingAddress => _shippingAddress;
List<PackagesCartItemsResponseModel> get orderItems => _orderItems;
String get orderStatus => _orderStatus;
String get paymentStatus => _paymentStatus;
String get shippingStatus => _shippingStatus;
String get customerTaxDisplayType => _customerTaxDisplayType;
int get id => _id;
OrderResponseModel({
String customOrderNumber,
int storeId,
dynamic pickUpInStore,
String paymentMethodSystemName,
String customerCurrencyCode,
double currencyRate,
int customerTaxDisplayTypeId,
dynamic vatNumber,
double orderSubtotalInclTax,
double orderSubtotalExclTax,
double orderSubTotalDiscountInclTax,
double orderSubTotalDiscountExclTax,
double orderShippingInclTax,
double orderShippingExclTax,
double paymentMethodAdditionalFeeInclTax,
double paymentMethodAdditionalFeeExclTax,
String taxRates,
double orderTax,
double orderDiscount,
double orderTotal,
double refundedAmount,
dynamic rewardPointsWereAdded,
String checkoutAttributeDescription,
int customerLanguageId,
int affiliateId,
String customerIp,
dynamic authorizationTransactionId,
dynamic authorizationTransactionCode,
dynamic authorizationTransactionResult,
dynamic captureTransactionId,
dynamic captureTransactionResult,
dynamic subscriptionTransactionId,
dynamic paidDateUtc,
dynamic shippingMethod,
dynamic shippingRateComputationMethodSystemName,
String customValuesXml,
dynamic paymentOption,
bool deleted,
String createdOnUtc,
PackagesCustomerResponseModel customer,
int customerId,
dynamic billingAddress,
dynamic shippingAddress,
List<PackagesCartItemsResponseModel> orderItems,
String orderStatus,
String paymentStatus,
String shippingStatus,
String customerTaxDisplayType,
int id}){
_customOrderNumber = customOrderNumber;
_storeId = storeId;
_pickUpInStore = pickUpInStore;
_paymentMethodSystemName = paymentMethodSystemName;
_customerCurrencyCode = customerCurrencyCode;
_currencyRate = currencyRate;
_customerTaxDisplayTypeId = customerTaxDisplayTypeId;
_vatNumber = vatNumber;
_orderSubtotalInclTax = orderSubtotalInclTax;
_orderSubtotalExclTax = orderSubtotalExclTax;
_orderSubTotalDiscountInclTax = orderSubTotalDiscountInclTax;
_orderSubTotalDiscountExclTax = orderSubTotalDiscountExclTax;
_orderShippingInclTax = orderShippingInclTax;
_orderShippingExclTax = orderShippingExclTax;
_paymentMethodAdditionalFeeInclTax = paymentMethodAdditionalFeeInclTax;
_paymentMethodAdditionalFeeExclTax = paymentMethodAdditionalFeeExclTax;
_taxRates = taxRates;
_orderTax = orderTax;
_orderDiscount = orderDiscount;
_orderTotal = orderTotal;
_refundedAmount = refundedAmount;
_rewardPointsWereAdded = rewardPointsWereAdded;
_checkoutAttributeDescription = checkoutAttributeDescription;
_customerLanguageId = customerLanguageId;
_affiliateId = affiliateId;
_customerIp = customerIp;
_authorizationTransactionId = authorizationTransactionId;
_authorizationTransactionCode = authorizationTransactionCode;
_authorizationTransactionResult = authorizationTransactionResult;
_captureTransactionId = captureTransactionId;
_captureTransactionResult = captureTransactionResult;
_subscriptionTransactionId = subscriptionTransactionId;
_paidDateUtc = paidDateUtc;
_shippingMethod = shippingMethod;
_shippingRateComputationMethodSystemName = shippingRateComputationMethodSystemName;
_customValuesXml = customValuesXml;
_paymentOption = paymentOption;
_deleted = deleted;
_createdOnUtc = createdOnUtc;
_customer = customer;
_customerId = customerId;
_billingAddress = billingAddress;
_shippingAddress = shippingAddress;
_orderItems = orderItems;
_orderStatus = orderStatus;
_paymentStatus = paymentStatus;
_shippingStatus = shippingStatus;
_customerTaxDisplayType = customerTaxDisplayType;
_id = id;
}
PackagesOrderResponseModel.fromJson(dynamic json) {
_customOrderNumber = json["custom_order_number"];
_storeId = json["store_id"];
_pickUpInStore = json["pick_up_in_store"];
_paymentMethodSystemName = json["payment_method_system_name"];
_customerCurrencyCode = json["customer_currency_code"];
_currencyRate = json["currency_rate"];
_customerTaxDisplayTypeId = json["customer_tax_display_type_id"];
_vatNumber = json["vat_number"];
_orderSubtotalInclTax = json["order_subtotal_incl_tax"];
_orderSubtotalExclTax = json["order_subtotal_excl_tax"];
_orderSubTotalDiscountInclTax = json["order_sub_total_discount_incl_tax"];
_orderSubTotalDiscountExclTax = json["order_sub_total_discount_excl_tax"];
_orderShippingInclTax = json["order_shipping_incl_tax"];
_orderShippingExclTax = json["order_shipping_excl_tax"];
_paymentMethodAdditionalFeeInclTax = json["payment_method_additional_fee_incl_tax"];
_paymentMethodAdditionalFeeExclTax = json["payment_method_additional_fee_excl_tax"];
_taxRates = json["tax_rates"];
_orderTax = json["order_tax"];
_orderDiscount = json["order_discount"];
_orderTotal = json["order_total"];
_refundedAmount = json["refunded_amount"];
_rewardPointsWereAdded = json["reward_points_were_added"];
_checkoutAttributeDescription = json["checkout_attribute_description"];
_customerLanguageId = json["customer_language_id"];
_affiliateId = json["affiliate_id"];
_customerIp = json["customer_ip"];
_authorizationTransactionId = json["authorization_transaction_id"];
_authorizationTransactionCode = json["authorization_transaction_code"];
_authorizationTransactionResult = json["authorization_transaction_result"];
_captureTransactionId = json["capture_transaction_id"];
_captureTransactionResult = json["capture_transaction_result"];
_subscriptionTransactionId = json["subscription_transaction_id"];
_paidDateUtc = json["paid_date_utc"];
_shippingMethod = json["shipping_method"];
_shippingRateComputationMethodSystemName = json["shipping_rate_computation_method_system_name"];
_customValuesXml = json["custom_values_xml"];
_paymentOption = json["payment_option"];
_deleted = json["deleted"];
_createdOnUtc = json["created_on_utc"];
_customer = json["customer"] != null ? PackagesCustomerResponseModel.fromJson(json["customer"]) : null;
_customerId = json["customer_id"];
_billingAddress = json["billing_address"];
_shippingAddress = json["shipping_address"];
if (json["order_items"] != null) {
_orderItems = [];
json["order_items"].forEach((v) {
_orderItems.add(PackagesCartItemsResponseModel.fromJson(v));
});
}
_orderStatus = json["order_status"];
_paymentStatus = json["payment_status"];
_shippingStatus = json["shipping_status"];
_customerTaxDisplayType = json["customer_tax_display_type"];
_id = json["id"];
}
Map<String, dynamic> toJson() {
var map = <String, dynamic>{};
map["custom_order_number"] = _customOrderNumber;
map["store_id"] = _storeId;
map["pick_up_in_store"] = _pickUpInStore;
map["payment_method_system_name"] = _paymentMethodSystemName;
map["customer_currency_code"] = _customerCurrencyCode;
map["currency_rate"] = _currencyRate;
map["customer_tax_display_type_id"] = _customerTaxDisplayTypeId;
map["vat_number"] = _vatNumber;
map["order_subtotal_incl_tax"] = _orderSubtotalInclTax;
map["order_subtotal_excl_tax"] = _orderSubtotalExclTax;
map["order_sub_total_discount_incl_tax"] = _orderSubTotalDiscountInclTax;
map["order_sub_total_discount_excl_tax"] = _orderSubTotalDiscountExclTax;
map["order_shipping_incl_tax"] = _orderShippingInclTax;
map["order_shipping_excl_tax"] = _orderShippingExclTax;
map["payment_method_additional_fee_incl_tax"] = _paymentMethodAdditionalFeeInclTax;
map["payment_method_additional_fee_excl_tax"] = _paymentMethodAdditionalFeeExclTax;
map["tax_rates"] = _taxRates;
map["order_tax"] = _orderTax;
map["order_discount"] = _orderDiscount;
map["order_total"] = _orderTotal;
map["refunded_amount"] = _refundedAmount;
map["reward_points_were_added"] = _rewardPointsWereAdded;
map["checkout_attribute_description"] = _checkoutAttributeDescription;
map["customer_language_id"] = _customerLanguageId;
map["affiliate_id"] = _affiliateId;
map["customer_ip"] = _customerIp;
map["authorization_transaction_id"] = _authorizationTransactionId;
map["authorization_transaction_code"] = _authorizationTransactionCode;
map["authorization_transaction_result"] = _authorizationTransactionResult;
map["capture_transaction_id"] = _captureTransactionId;
map["capture_transaction_result"] = _captureTransactionResult;
map["subscription_transaction_id"] = _subscriptionTransactionId;
map["paid_date_utc"] = _paidDateUtc;
map["shipping_method"] = _shippingMethod;
map["shipping_rate_computation_method_system_name"] = _shippingRateComputationMethodSystemName;
map["custom_values_xml"] = _customValuesXml;
map["payment_option"] = _paymentOption;
map["deleted"] = _deleted;
map["created_on_utc"] = _createdOnUtc;
if (_customer != null) {
map["customer"] = _customer.toJson();
}
map["customer_id"] = _customerId;
map["billing_address"] = _billingAddress;
map["shipping_address"] = _shippingAddress;
if (_orderItems != null) {
map["order_items"] = _orderItems.map((v) => v.toJson()).toList();
}
map["order_status"] = _orderStatus;
map["payment_status"] = _paymentStatus;
map["shipping_status"] = _shippingStatus;
map["customer_tax_display_type"] = _customerTaxDisplayType;
map["id"] = _id;
return map;
}
}

@ -3,6 +3,8 @@ import 'dart:developer';
import 'dart:ui'; import 'dart:ui';
import 'package:diplomaticquarterapp/config/config.dart'; import 'package:diplomaticquarterapp/config/config.dart';
import 'package:diplomaticquarterapp/core/enum/PaymentOptions.dart';
import 'package:diplomaticquarterapp/core/model/ResponseModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/requests/AddProductToCartRequestModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/requests/AddProductToCartRequestModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/requests/CreateCustomerRequestModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/requests/CreateCustomerRequestModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/requests/OffersCategoriesRequestModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/requests/OffersCategoriesRequestModel.dart';
@ -11,6 +13,7 @@ import 'package:diplomaticquarterapp/core/model/packages_offers/responses/Packag
import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesCategoriesResponseModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesCategoriesResponseModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesResponseModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesResponseModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesCustomerResponseModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesCustomerResponseModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/responses/order_response_model.dart';
import 'package:diplomaticquarterapp/core/service/base_service.dart'; import 'package:diplomaticquarterapp/core/service/base_service.dart';
import 'package:diplomaticquarterapp/core/service/client/base_app_client.dart'; import 'package:diplomaticquarterapp/core/service/client/base_app_client.dart';
import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart';
@ -24,7 +27,8 @@ class OffersAndPackagesServices extends BaseService {
List<PackagesResponseModel> latestOffersList = List(); List<PackagesResponseModel> latestOffersList = List();
List<PackagesResponseModel> bestSellerList = List(); List<PackagesResponseModel> bestSellerList = List();
List<PackagesResponseModel> bannersList = List(); List<PackagesResponseModel> bannersList = List();
List<CartProductResponseModel> cartItemList = List(); List<PackagesCartItemsResponseModel> cartItemList = List();
String cartItemCount = "";
PackagesCustomerResponseModel customer; PackagesCustomerResponseModel customer;
@ -154,15 +158,15 @@ class OffersAndPackagesServices extends BaseService {
// -------------------- // --------------------
// Create Customer // Create Customer
// -------------------- // --------------------
Future<PackagesCustomerResponseModel> createCustomer(PackagesCustomerRequestModel request, {@required BuildContext context, bool showLoading = true, Function(bool) completion }) async{ Future createCustomer(PackagesCustomerRequestModel request, {@required BuildContext context, bool showLoading = true, Function(bool) completion }) async{
if(customer != null) if(customer != null)
return Future.value(customer); return Future.value(customer);
hasError = false;
var url = EXA_CART_API_BASE_URL + PACKAGES_CUSTOMER;
customer = null; customer = null;
Future errorThrow;
_showLoading(context, showLoading); _showLoading(context, showLoading);
var url = EXA_CART_API_BASE_URL + PACKAGES_CUSTOMER;
await baseAppClient.simplePost(url, body: request.json(), onSuccess: (dynamic stringResponse, int statusCode){ await baseAppClient.simplePost(url, body: request.json(), onSuccess: (dynamic stringResponse, int statusCode){
_hideLoading(context, showLoading); _hideLoading(context, showLoading);
@ -172,10 +176,13 @@ class OffersAndPackagesServices extends BaseService {
}, onFailure: (String error, int statusCode){ }, onFailure: (String error, int statusCode){
_hideLoading(context, showLoading); _hideLoading(context, showLoading);
errorThrow = Future.error(error);
log(error); log(error);
}); });
return customer; await Future.delayed(Duration(seconds: 1));
return errorThrow ?? customer;
} }
@ -183,7 +190,7 @@ class OffersAndPackagesServices extends BaseService {
// -------------------- // --------------------
// Shopping Cart // Shopping Cart
// -------------------- // --------------------
Future<List<CartProductResponseModel>> cartItems({@required BuildContext context, bool showLoading = true}) async{ Future<List<PackagesCartItemsResponseModel>> cartItems({@required BuildContext context, bool showLoading = true}) async{
Future errorThrow; Future errorThrow;
cartItemList.clear(); cartItemList.clear();
@ -194,7 +201,7 @@ class OffersAndPackagesServices extends BaseService {
var jsonResponse = json.decode(stringResponse); var jsonResponse = json.decode(stringResponse);
jsonResponse['shopping_carts'].forEach((json) { jsonResponse['shopping_carts'].forEach((json) {
cartItemList.add(CartProductResponseModel.fromJson(json)); cartItemList.add(PackagesCartItemsResponseModel.fromJson(json));
}); });
}, onFailure: (String error, int statusCode) { }, onFailure: (String error, int statusCode) {
@ -206,8 +213,9 @@ class OffersAndPackagesServices extends BaseService {
return errorThrow ?? cartItemList; return errorThrow ?? cartItemList;
} }
Future addProductToCart(AddProductToCartRequestModel request, {@required BuildContext context, bool showLoading = true}) async{ Future<ResponseModel<PackagesCartItemsResponseModel>> addProductToCart(AddProductToCartRequestModel request, {@required BuildContext context, bool showLoading = true}) async{
Future errorThrow; Future errorThrow;
ResponseModel<PackagesCartItemsResponseModel> response;
request.customer_id = customer.id; request.customer_id = customer.id;
@ -217,14 +225,16 @@ class OffersAndPackagesServices extends BaseService {
_hideLoading(context, showLoading); _hideLoading(context, showLoading);
var jsonResponse = json.decode(stringResponse); var jsonResponse = json.decode(stringResponse);
var jsonCartItem = jsonResponse["shopping_carts"][0];
response = ResponseModel(status: true, data: PackagesCartItemsResponseModel.fromJson(jsonCartItem), error: null);
cartItemCount = response.data.quantity.toString();
}, onFailure: (String error, int statusCode){ }, onFailure: (String error, int statusCode){
_hideLoading(context, showLoading); _hideLoading(context, showLoading);
log(error); errorThrow = Future.error(ResponseModel(status: true, data: null, error: error));
errorThrow = Future.error(error);
}); });
return errorThrow ?? true; return errorThrow ?? response;
} }
Future updateProductToCart(int cartItemID, {UpdateProductToCartRequestModel request, @required BuildContext context, bool showLoading = true}) async{ Future updateProductToCart(int cartItemID, {UpdateProductToCartRequestModel request, @required BuildContext context, bool showLoading = true}) async{
@ -268,21 +278,29 @@ class OffersAndPackagesServices extends BaseService {
// -------------------- // --------------------
// Place Order // Place Order
// -------------------- // --------------------
Future placeOrder({@required BuildContext context, bool showLoading = true}) async{ Future placeOrder({@required String paymentOption, @required BuildContext context, bool showLoading = true}) async{
Future errorThrow; Future errorThrow;
var jsonBody = { var jsonBody = {
"order": { "order": {
"customer_id" : customer.id "customer_id" : customer.id,
"billing_address": {
"email": customer.email,
"phone_number": customer.addresses.first.phoneNumber
},
"payment_method_system_name": "Payments.PayFort",
"payment_option": paymentOption
} }
}; };
int order_id;
_showLoading(context, showLoading); _showLoading(context, showLoading);
var url = EXA_CART_API_BASE_URL + PACKAGES_SHOPPING_CART; var url = EXA_CART_API_BASE_URL + PACKAGES_ORDERS;
await baseAppClient.simplePost(url, body: jsonBody, onSuccess: (dynamic stringResponse, int statusCode){ await baseAppClient.simplePost(url, body: jsonBody, onSuccess: (dynamic stringResponse, int statusCode){
_hideLoading(context, showLoading); _hideLoading(context, showLoading);
var jsonResponse = json.decode(stringResponse); var jsonResponse = json.decode(stringResponse);
order_id = jsonResponse['orders'][0]['id'];
}, onFailure: (String error, int statusCode){ }, onFailure: (String error, int statusCode){
_hideLoading(context, showLoading); _hideLoading(context, showLoading);
@ -290,7 +308,28 @@ class OffersAndPackagesServices extends BaseService {
errorThrow = Future.error(error); errorThrow = Future.error(error);
}); });
return errorThrow ?? true; return errorThrow ?? order_id;
}
Future<ResponseModel<PackagesOrderResponseModel>> getOrderById(int id, {@required BuildContext context, bool showLoading = true}) async{
Future errorThrow;
ResponseModel<PackagesOrderResponseModel> response;
_showLoading(context, showLoading);
var url = EXA_CART_API_BASE_URL + PACKAGES_ORDERS + '/$id';
await baseAppClient.simpleGet(url, onSuccess: (dynamic stringResponse, int statusCode) {
_hideLoading(context, showLoading);
var jsonResponse = json.decode(stringResponse);
var jsonOrder = jsonResponse['orders'][0];
response = ResponseModel(status: true, data: PackagesOrderResponseModel.fromJson(jsonOrder));
}, onFailure: (String error, int statusCode) {
_hideLoading(context, showLoading);
errorThrow = Future.error(ResponseModel(status: false,error: error));
}, queryParams: null);
return errorThrow ?? response;
} }
} }

@ -9,10 +9,11 @@ import 'package:diplomaticquarterapp/core/viewModels/base_view_model.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:diplomaticquarterapp/locator.dart'; import 'package:diplomaticquarterapp/locator.dart';
class OfferCategoriesViewModel extends BaseViewModel { class OfferCategoriesViewModel extends BaseViewModel{
OffersAndPackagesServices service = locator<OffersAndPackagesServices>(); OffersAndPackagesServices service = locator<OffersAndPackagesServices>();
get categoryList => service.categoryList; get categoryList => service.categoryList;
get productList => service.categoryList; get productList => service.categoryList;
} }
class PackagesViewModel extends BaseViewModel { class PackagesViewModel extends BaseViewModel {
@ -22,5 +23,15 @@ class PackagesViewModel extends BaseViewModel {
List<PackagesResponseModel> get latestOffersList => service.latestOffersList; List<PackagesResponseModel> get latestOffersList => service.latestOffersList;
List<PackagesResponseModel> get bestSellerList => service.bestSellerList; List<PackagesResponseModel> get bestSellerList => service.bestSellerList;
List<PackagesResponseModel> get bannersList => service.bannersList; List<PackagesResponseModel> get bannersList => service.bannersList;
List<CartProductResponseModel> get cartItemList => service.cartItemList; List<PackagesCartItemsResponseModel> get cartItemList => service.cartItemList;
String _cartItemCount = "";
String get cartItemCount => _cartItemCount;
set cartItemCount(String value) {
_cartItemCount = value;
notifyListeners();
}
} }

@ -60,7 +60,6 @@ class MyApp extends StatelessWidget {
], ],
child: Consumer<ProjectViewModel>( child: Consumer<ProjectViewModel>(
builder: (context, projectProvider, child) => MaterialApp( builder: (context, projectProvider, child) => MaterialApp(
showSemanticsDebugger: false, showSemanticsDebugger: false,
title: 'Diplomatic Quarter App', title: 'Diplomatic Quarter App',
locale: projectProvider.appLocal, locale: projectProvider.appLocal,
@ -91,6 +90,7 @@ class MyApp extends StatelessWidget {
color: Color(0xffB8382C), color: Color(0xffB8382C),
), ),
), ),
floatingActionButtonTheme: FloatingActionButtonThemeData(highlightElevation: 2, disabledElevation: 0, elevation: 2),
disabledColor: Colors.grey[300], disabledColor: Colors.grey[300],
errorColor: Color.fromRGBO(235, 80, 60, 1.0), errorColor: Color.fromRGBO(235, 80, 60, 1.0),
scaffoldBackgroundColor: Color(0xffE9E9E9), // Colors.grey[100], scaffoldBackgroundColor: Color(0xffE9E9E9), // Colors.grey[100],
@ -115,8 +115,9 @@ class MyApp extends StatelessWidget {
), ),
), ),
), ),
// initialRoute: SPLASH, initialRoute: SPLASH,
initialRoute: PACKAGES_OFFERS, // initialRoute: PACKAGES_OFFERS,
// initialRoute: PACKAGES_ORDER_COMPLETED,
routes: routes, routes: routes,
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
), ),

@ -10,6 +10,7 @@ import 'package:diplomaticquarterapp/pages/Covid-DriveThru/covid-drivethru-locat
import 'package:diplomaticquarterapp/pages/ErService/ErOptions.dart'; import 'package:diplomaticquarterapp/pages/ErService/ErOptions.dart';
import 'package:diplomaticquarterapp/pages/base/base_view.dart'; import 'package:diplomaticquarterapp/pages/base/base_view.dart';
import 'package:diplomaticquarterapp/pages/livecare/livecare_home.dart'; import 'package:diplomaticquarterapp/pages/livecare/livecare_home.dart';
import 'package:diplomaticquarterapp/pages/packages_offers/OfferAndPackagesPage.dart';
import 'package:diplomaticquarterapp/pages/paymentService/payment_service.dart'; import 'package:diplomaticquarterapp/pages/paymentService/payment_service.dart';
import 'package:diplomaticquarterapp/pages/pharmacies/screens/pharmacy_module_page.dart'; import 'package:diplomaticquarterapp/pages/pharmacies/screens/pharmacy_module_page.dart';
import 'package:diplomaticquarterapp/uitl/date_uitl.dart'; import 'package:diplomaticquarterapp/uitl/date_uitl.dart';
@ -410,6 +411,34 @@ class _HomePageState extends State<HomePage> {
), ),
], ],
), ),
Padding(
padding: const EdgeInsets.only(bottom: 15, right: 15, left: 15),
child: InkWell(
onTap: (){
Navigator.of(context).push(MaterialPageRoute(builder: (context) => PackagesHomePage()));
},
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Color(0xffB8382C),
),
child: Padding(
padding: const EdgeInsets.all(8),
child: Row(
children: [
Text(
TranslationBase.of(context).offerAndPackages,
style: TextStyle(color: Colors.white, fontSize: 20, fontWeight: FontWeight.normal),
),
Spacer(),
Image.asset("assets/images/offer_icon.png"),
],
),
),
),
),
),
if(projectViewModel.havePrivilege(64)||projectViewModel.havePrivilege(65)||projectViewModel.havePrivilege(67)) if(projectViewModel.havePrivilege(64)||projectViewModel.havePrivilege(65)||projectViewModel.havePrivilege(67))
Container( Container(
margin: EdgeInsets.only(left: 15, right: 15), margin: EdgeInsets.only(left: 15, right: 15),

@ -1,4 +1,6 @@
import 'package:after_layout/after_layout.dart';
import 'package:carousel_slider/carousel_slider.dart'; import 'package:carousel_slider/carousel_slider.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/requests/AddProductToCartRequestModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/requests/OffersCategoriesRequestModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/requests/OffersCategoriesRequestModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/requests/OffersProductsRequestModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/requests/OffersProductsRequestModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesCategoriesResponseModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesCategoriesResponseModel.dart';
@ -21,6 +23,8 @@ import 'package:flutter/rendering.dart';
import 'package:flutter_material_pickers/flutter_material_pickers.dart'; import 'package:flutter_material_pickers/flutter_material_pickers.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'CreateCustomerDailogPage.dart';
dynamic languageID; dynamic languageID;
class ClinicPackagesPage extends StatefulWidget { class ClinicPackagesPage extends StatefulWidget {
@ -33,15 +37,39 @@ class ClinicPackagesPage extends StatefulWidget {
} }
class _ClinicPackagesPageState extends State<ClinicPackagesPage> { class _ClinicPackagesPageState extends State<ClinicPackagesPage> with AfterLayoutMixin<ClinicPackagesPage>{
List<PackagesResponseModel> get _products => widget.products; AppScaffold appScaffold;
List<PackagesResponseModel> get _products => widget.products;
PackagesViewModel viewModel; PackagesViewModel viewModel;
onProductCartClick(PackagesResponseModel product) async {
if(viewModel.service.customer == null)
viewModel.service.customer = await CreateCustomerDialogPage(context: context).show();
if(viewModel.service.customer != null) {
var request = AddProductToCartRequestModel(product_id: product.id, customer_id: viewModel.service.customer.id);
await viewModel.service.addProductToCart(request, context: context).then((response){
appScaffold.appBar.badgeUpdater(viewModel.service.cartItemCount);
}).catchError((error) {
utils.Utils.showErrorToast(error);
});
}
}
@override
void afterFirstLayout(BuildContext context) async{
appScaffold.appBar.badgeUpdater(viewModel.service.cartItemCount);
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -50,7 +78,7 @@ class _ClinicPackagesPageState extends State<ClinicPackagesPage> {
onModelReady: (model){ onModelReady: (model){
viewModel = model; viewModel = model;
}, },
builder: (_, model, wi) => AppScaffold( builder: (_, model, wi) => appScaffold = AppScaffold(
appBarTitle: TranslationBase.of(context).offerAndPackages, appBarTitle: TranslationBase.of(context).offerAndPackages,
isShowAppBar: true, isShowAppBar: true,
isPharmacy: false, isPharmacy: false,
@ -66,7 +94,7 @@ class _ClinicPackagesPageState extends State<ClinicPackagesPage> {
itemCount: _products.length, itemCount: _products.length,
itemBuilder: (BuildContext context, int index) => new Container( itemBuilder: (BuildContext context, int index) => new Container(
color: Colors.transparent, color: Colors.transparent,
child: PackagesItemCard( itemContentPadding: 10,itemModel: _products[index],) child: PackagesItemCard( itemContentPadding: 10,itemModel: _products[index], onCartClick: onProductCartClick,)
), ),
staggeredTileBuilder: (int index) => StaggeredTile.fit(2), staggeredTileBuilder: (int index) => StaggeredTile.fit(2),
mainAxisSpacing: 20, mainAxisSpacing: 20,

@ -0,0 +1,206 @@
import 'package:after_layout/after_layout.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:diplomaticquarterapp/config/size_config.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/requests/AddProductToCartRequestModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/requests/CreateCustomerRequestModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/requests/OffersCategoriesRequestModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/requests/OffersProductsRequestModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesCustomerResponseModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesResponseModel.dart';
import 'package:diplomaticquarterapp/core/viewModels/packages_offers/PackagesOffersViewModel.dart';
import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/order_model_view_model.dart';
import 'package:diplomaticquarterapp/locator.dart';
import 'package:diplomaticquarterapp/pages/base/base_view.dart';
import 'package:diplomaticquarterapp/pages/packages_offers/ClinicOfferAndPackagesPage.dart';
import 'package:diplomaticquarterapp/pages/packages_offers/OfferAndPackageDetailPage.dart';
import 'package:diplomaticquarterapp/pages/packages_offers/OfferAndPackagesCartPage.dart';
import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart';
import 'package:diplomaticquarterapp/uitl/utils.dart' as utils;
import 'package:diplomaticquarterapp/widgets/AnimatedTextFields.dart';
import 'package:diplomaticquarterapp/widgets/Loader/gif_loader_container.dart';
import 'package:diplomaticquarterapp/widgets/LoadingButton.dart';
import 'package:diplomaticquarterapp/widgets/carousel_indicator/carousel_indicator.dart';
import 'package:diplomaticquarterapp/widgets/loadings/ShimmerLoading.dart';
import 'package:diplomaticquarterapp/widgets/offers_packages/PackagesOfferCard.dart';
import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart';
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:diplomaticquarterapp/config/shared_pref_kay.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_material_pickers/flutter_material_pickers.dart';
dynamic languageID;
var emailRegex = RegExp(r'^[^\s@]+@[^\s@]+\.[^\s@]+$');
class CreateCustomerDialogPage extends StatefulWidget {
final BuildContext context;
CreateCustomerDialogPage({this.context});
PackagesViewModel viewModel;
Future<PackagesCustomerResponseModel> show() async{
await showDialog(context: context, builder: (context ){
return AlertDialog(content: this, shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)
), elevation: 5, );
});
return viewModel.service.customer;
}
@override
_CreateCustomerDialogPageState createState() => _CreateCustomerDialogPageState();
}
class _CreateCustomerDialogPageState extends State<CreateCustomerDialogPage> with AfterLayoutMixin<CreateCustomerDialogPage>, TickerProviderStateMixin{
AnimationController _loadingController;
AnimationController _submitController;
bool _enableInput = true;
Interval _nameTextFieldLoadingAnimationInterval = const Interval(0, .85);
final _phoneFocusNode = FocusNode();
@override
void initState() {
_submitController = AnimationController(vsync: this, duration: Duration(milliseconds: 1000),);
super.initState();
}
@override
void afterFirstLayout(BuildContext context) async{
}
// Controllers
TextEditingController _emailTextController = TextEditingController();
TextEditingController _phoneTextController = TextEditingController();
TextEditingController _emailPinTextController = TextEditingController();
TextEditingController _phonePinTextController = TextEditingController();
bool verifyPin = false;
PackagesViewModel viewModel() => widget.viewModel;
@override
Widget build(BuildContext context) {
return BaseView<PackagesViewModel>(
allowAny: true,
onModelReady: (model) => widget.viewModel = model,
builder: (_, model, wi) => verifyPin ? verifyPinWidget() : userDetailWidget()
);
}
Widget verifyPinWidget(){
}
Widget userDetailWidget(){
return
Container(
width: SizeConfig.realScreenWidth * 0.8,
height: 270,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text("Create Guest Customer"),
SizedBox(height: 30,),
AnimatedTextFormField(
enabled: _enableInput,
controller: _emailTextController,
width: 100,
loadingController: _loadingController,
interval: _nameTextFieldLoadingAnimationInterval,
labelText: "Email",
prefixIcon: Icon(Icons.email),
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.next,
onFieldSubmitted: (value) {
FocusScope.of(context).requestFocus(_phoneFocusNode);
},
validator: (value){
return (value.isEmpty || !emailRegex.hasMatch(value))
? 'Invalid email!'
: null;
},
),
SizedBox(height: 30,),
AnimatedTextFormField(
enabled: _enableInput,
controller: _phoneTextController,
width: 100,
loadingController: _loadingController,
interval: _nameTextFieldLoadingAnimationInterval,
labelText: "Mobile Number",
prefixIcon: Icon(Icons.phone_android),
keyboardType: TextInputType.phone,
textInputAction: TextInputAction.next,
onFieldSubmitted: (value) {
FocusScope.of(context).requestFocus(_phoneFocusNode);
},
validator: (value){
return (value.isEmpty || !emailRegex.hasMatch(value))
? 'Invalid email!'
: null;
},
),
Spacer(flex: 1,),
AnimatedButton(
color: Theme.of(context).primaryColor,
loadingColor: Theme.of(context).primaryColor,
controller: _submitController,
text: TranslationBase.of(context).done,
onPressed: (){
createCustomer();
},
)
// RaisedButton(
// child: Text(
// TranslationBase.of(context).done,
// style: TextStyle(fontSize: 15, color: Colors.white, fontWeight: FontWeight.bold),
// ),
// padding: EdgeInsets.only(top: 5, bottom: 5, left: 0, right: 0),
// shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5), side: BorderSide(color: Theme.of(context).primaryColor, width: 0.5)),
// color: Theme.of(context).primaryColor,
// onPressed: (){
//
// },
// )
,
],
),
);
}
createCustomer() async{
setState(() => _enableInput = false);
loading(true);
var request = PackagesCustomerRequestModel(email: _emailTextController.text, phoneNumber: _phoneTextController.text);
viewModel().service
.createCustomer(request, context: context, showLoading: false)
.then((value) => success())
.catchError((error) => showError(error));
}
success() async{
loading(false);
await Future.delayed(Duration(seconds: 2));
Navigator.of(context).pop();
}
showError(String errorMessage) async{
loading(false);
setState(() => _enableInput = true);
}
loading(bool can){
can ? _submitController.forward() : _submitController.reverse();
}
}

@ -1,5 +1,7 @@
import 'package:after_layout/after_layout.dart'; import 'package:after_layout/after_layout.dart';
import 'package:carousel_slider/carousel_slider.dart'; import 'package:carousel_slider/carousel_slider.dart';
import 'package:diplomaticquarterapp/core/enum/PaymentOptions.dart';
import 'package:diplomaticquarterapp/core/model/ResponseModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/requests/AddProductToCartRequestModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/requests/AddProductToCartRequestModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/requests/OffersCategoriesRequestModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/requests/OffersCategoriesRequestModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/requests/OffersProductsRequestModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/requests/OffersProductsRequestModel.dart';
@ -9,11 +11,13 @@ import 'package:diplomaticquarterapp/locator.dart';
import 'package:diplomaticquarterapp/pages/base/base_view.dart'; import 'package:diplomaticquarterapp/pages/base/base_view.dart';
import 'package:diplomaticquarterapp/pages/packages_offers/ClinicOfferAndPackagesPage.dart'; import 'package:diplomaticquarterapp/pages/packages_offers/ClinicOfferAndPackagesPage.dart';
import 'package:diplomaticquarterapp/pages/packages_offers/OfferAndPackageDetailPage.dart'; import 'package:diplomaticquarterapp/pages/packages_offers/OfferAndPackageDetailPage.dart';
import 'package:diplomaticquarterapp/pages/packages_offers/PackageOrderCompletedPage.dart';
import 'package:diplomaticquarterapp/pages/pharmacies/screens/pharmacy-terms-conditions-page.dart'; import 'package:diplomaticquarterapp/pages/pharmacies/screens/pharmacy-terms-conditions-page.dart';
import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart';
import 'package:diplomaticquarterapp/uitl/utils.dart' as utils; import 'package:diplomaticquarterapp/uitl/utils.dart' as utils;
import 'package:diplomaticquarterapp/widgets/Loader/gif_loader_container.dart'; import 'package:diplomaticquarterapp/widgets/Loader/gif_loader_container.dart';
import 'package:diplomaticquarterapp/widgets/carousel_indicator/carousel_indicator.dart'; import 'package:diplomaticquarterapp/widgets/carousel_indicator/carousel_indicator.dart';
import 'package:diplomaticquarterapp/widgets/in_app_browser/InAppBrowser.dart';
import 'package:diplomaticquarterapp/widgets/loadings/ShimmerLoading.dart'; import 'package:diplomaticquarterapp/widgets/loadings/ShimmerLoading.dart';
import 'package:diplomaticquarterapp/widgets/offers_packages/PackagesCartItemCard.dart'; import 'package:diplomaticquarterapp/widgets/offers_packages/PackagesCartItemCard.dart';
import 'package:diplomaticquarterapp/widgets/offers_packages/PackagesOfferCard.dart'; import 'package:diplomaticquarterapp/widgets/offers_packages/PackagesOfferCard.dart';
@ -73,7 +77,21 @@ class _PackagesCartPageState extends State<PackagesCartPage> with AfterLayoutMix
} }
onPayNowClick() async{ onPayNowClick() async{
await viewModel.service.placeOrder(context: context); await viewModel.service.placeOrder(context: context,paymentOption: _selectedPaymentMethod.toUpperCase()).then((orderId){
if(orderId.runtimeType == int){ // result == order_id
var browser = MyInAppBrowser(
context: context,
onExitCallback: (data, isDone) => paymentClosed(orderId: orderId, withStatus: isDone, data: data)
);
browser.openPackagesPaymentBrowser(customer_id: viewModel.service.customer.id, order_id: orderId);
}else{
utils.Utils.showErrorToast('Failed to place order, please try again later');
}
}).catchError((error){
utils.Utils.showErrorToast(error);
});
} }
@override @override
@ -124,10 +142,10 @@ class _PackagesCartPageState extends State<PackagesCartPage> with AfterLayoutMix
itemModel: item, itemModel: item,
shouldStepperChangeApply: (apply,total) async{ shouldStepperChangeApply: (apply,total) async{
var request = AddProductToCartRequestModel(product_id: item.productId, quantity: apply); var request = AddProductToCartRequestModel(product_id: item.productId, quantity: apply);
bool success = await viewModel.service.addProductToCart(request, context: context, showLoading: false).catchError((error){ ResponseModel response = await viewModel.service.addProductToCart(request, context: context, showLoading: false).catchError((error){
utils.Utils.showErrorToast(error); utils.Utils.showErrorToast(error);
}); });
return success ?? false; return response.status ?? false;
}, },
) )
); );
@ -180,13 +198,27 @@ class _PackagesCartPageState extends State<PackagesCartPage> with AfterLayoutMix
await viewModel.service.cartItems(context: context).catchError((error) {}); await viewModel.service.cartItems(context: context).catchError((error) {});
setState((){}); setState((){});
} }
paymentClosed({@required int orderId, @required bool withStatus, dynamic data}) async{
viewModel.service.getOrderById(orderId, context: context).then((value){
var heading = withStatus ? "Success" : "Failed";
var title = "Your order has been placed successfully";
var subTitle = "Order# ${value.data.customOrderNumber}";
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (context) => PackageOrderCompletedPage(heading: heading, title: title, subTitle: subTitle))
);
}).catchError((error){
debugPrint(error);
});
}
} }
// /* Payment Footer Widgets */ // /* Payment Footer Widgets */
// --------------------------- // ---------------------------
String _selectedPaymentMethod; String _selectedPaymentMethod;
Widget _paymentOptions(BuildContext context, Function(String) onSelected) { Widget _paymentOptions(BuildContext context, Function(String) onSelected) {
double height = 22; double height = 30;
Widget buttonContent(bool isSelected, String imageName) { Widget buttonContent(bool isSelected, String imageName) {
return Container( return Container(

@ -4,12 +4,14 @@ import 'package:diplomaticquarterapp/core/model/packages_offers/requests/AddProd
import 'package:diplomaticquarterapp/core/model/packages_offers/requests/CreateCustomerRequestModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/requests/CreateCustomerRequestModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/requests/OffersCategoriesRequestModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/requests/OffersCategoriesRequestModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/requests/OffersProductsRequestModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/requests/OffersProductsRequestModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesCustomerResponseModel.dart';
import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesResponseModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesResponseModel.dart';
import 'package:diplomaticquarterapp/core/viewModels/packages_offers/PackagesOffersViewModel.dart'; import 'package:diplomaticquarterapp/core/viewModels/packages_offers/PackagesOffersViewModel.dart';
import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/order_model_view_model.dart'; import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/order_model_view_model.dart';
import 'package:diplomaticquarterapp/locator.dart'; import 'package:diplomaticquarterapp/locator.dart';
import 'package:diplomaticquarterapp/pages/base/base_view.dart'; import 'package:diplomaticquarterapp/pages/base/base_view.dart';
import 'package:diplomaticquarterapp/pages/packages_offers/ClinicOfferAndPackagesPage.dart'; import 'package:diplomaticquarterapp/pages/packages_offers/ClinicOfferAndPackagesPage.dart';
import 'package:diplomaticquarterapp/pages/packages_offers/CreateCustomerDailogPage.dart';
import 'package:diplomaticquarterapp/pages/packages_offers/OfferAndPackageDetailPage.dart'; import 'package:diplomaticquarterapp/pages/packages_offers/OfferAndPackageDetailPage.dart';
import 'package:diplomaticquarterapp/pages/packages_offers/OfferAndPackagesCartPage.dart'; import 'package:diplomaticquarterapp/pages/packages_offers/OfferAndPackagesCartPage.dart';
import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart';
@ -85,120 +87,123 @@ class _PackagesHomePageState extends State<PackagesHomePage> with AfterLayoutMix
onProductCartClick(PackagesResponseModel product) async { onProductCartClick(PackagesResponseModel product) async {
if(viewModel.service.customer == null) if(viewModel.service.customer == null)
await viewModel.service.createCustomer(PackagesCustomerRequestModel(email: "zikambrani@gmail.com", phoneNumber: "0500409598"), context: context); viewModel.service.customer = await CreateCustomerDialogPage(context: context).show();
if(viewModel.service.customer != null){ if(viewModel.service.customer != null) {
var request = AddProductToCartRequestModel(product_id: product.id, customer_id: viewModel.service.customer.id); var request = AddProductToCartRequestModel(product_id: product.id, customer_id: viewModel.service.customer.id);
await viewModel.service.addProductToCart(request, context: context).catchError((error) { await viewModel.service.addProductToCart(request, context: context).then((response){
appScaffold.appBar.badgeUpdater(viewModel.service.cartItemCount);
}).catchError((error) {
utils.Utils.showErrorToast(error); utils.Utils.showErrorToast(error);
}); });
} }
} }
AppScaffold appScaffold;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BaseView<PackagesViewModel>( return BaseView<PackagesViewModel>(
allowAny: true, allowAny: true,
onModelReady: (model) => viewModel = model, onModelReady: (model) => viewModel = model,
builder: (_, model, wi){ builder: (_, model, wi){
return return
AppScaffold( appScaffold =
appBarTitle: TranslationBase.of(context).offerAndPackages, AppScaffold(
isShowAppBar: true, appBarTitle: TranslationBase.of(context).offerAndPackages,
isPharmacy: false, isShowAppBar: true,
showPharmacyCart: false, isPharmacy: false,
showHomeAppBarIcon: false, showPharmacyCart: false,
isOfferPackages: true, showHomeAppBarIcon: false,
showOfferPackagesCart: true, isOfferPackages: true,
isShowDecPage: false, showOfferPackagesCart: true,
body: ListView( isShowDecPage: false,
children: [ body: ListView(
children: [
// Top Banner Carousel
AspectRatio( // Top Banner Carousel
aspectRatio: 2.2/1, AspectRatio(
child: bannerCarousel() aspectRatio: 2.2/1,
), child: bannerCarousel()
),
Center(
child: CarouselIndicator( Center(
activeColor: Theme.of(context).appBarTheme.color, child: CarouselIndicator(
color: Colors.grey[300], activeColor: Theme.of(context).appBarTheme.color,
cornerRadius: 15, color: Colors.grey[300],
width: 15, height: 15, cornerRadius: 15,
count: _bannerCarousel.itemCount, width: 15, height: 15,
index: carouselIndicatorIndex, count: _bannerCarousel.itemCount,
onClick: (index){ index: carouselIndicatorIndex,
debugPrint('onClick at ${index}'); onClick: (index){
}, debugPrint('onClick at ${index}');
), },
),
SizedBox(height: 10,),
Padding(
padding: const EdgeInsets.all(15),
child: Column(
children: [
// Search Textfield
searchTextField(),
SizedBox(height: 10,),
// Filter Selection
filterOptionSelection(),
SizedBox(height: 20,),
// Horizontal Scrollable Cards
Text(
"Latest offers",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black87,
fontSize: 20
),
), ),
),
// Latest Offers Horizontal Scrollable List
AspectRatio( SizedBox(height: 10,),
aspectRatio: 1.3/1,
child: LayoutBuilder(builder: (context, constraints){ Padding(
double itemContentPadding = 10; padding: const EdgeInsets.all(15),
double itemWidth = (constraints.maxWidth/2) - (itemContentPadding*2); child: Column(
return latestOfferListView(itemWidth: itemWidth, itemContentPadding: itemContentPadding); children: [
}), // Search Textfield
), searchTextField(),
SizedBox(height: 10,), SizedBox(height: 10,),
Text( // Filter Selection
"Best sellers", filterOptionSelection(),
style: TextStyle(
fontWeight: FontWeight.bold, SizedBox(height: 20,),
color: Colors.black87,
fontSize: 20 // Horizontal Scrollable Cards
), Text(
), "Latest offers",
style: TextStyle(
fontWeight: FontWeight.bold,
// Best Seller Horizontal Scrollable List color: Colors.black87,
AspectRatio( fontSize: 20
aspectRatio: 1.3/1, ),
child: LayoutBuilder(builder: (context, constraints){ ),
double itemContentPadding = 10; // 10 is content padding in each item
double itemWidth = (constraints.maxWidth/2) - (itemContentPadding*2 /* 2 = LeftRight */); // Latest Offers Horizontal Scrollable List
return bestSellerListView(itemWidth: itemWidth, itemContentPadding: itemContentPadding); AspectRatio(
}), aspectRatio: 1.3/1,
) child: LayoutBuilder(builder: (context, constraints){
double itemContentPadding = 10;
],), double itemWidth = (constraints.maxWidth/2) - (itemContentPadding*2);
return latestOfferListView(itemWidth: itemWidth, itemContentPadding: itemContentPadding);
}),
),
SizedBox(height: 10,),
Text(
"Best sellers",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black87,
fontSize: 20
),
),
// Best Seller Horizontal Scrollable List
AspectRatio(
aspectRatio: 1.3/1,
child: LayoutBuilder(builder: (context, constraints){
double itemContentPadding = 10; // 10 is content padding in each item
double itemWidth = (constraints.maxWidth/2) - (itemContentPadding*2 /* 2 = LeftRight */);
return bestSellerListView(itemWidth: itemWidth, itemContentPadding: itemContentPadding);
}),
)
],),
),
],
), ),
], )
), .setOnAppBarCartClick(onCartClick);
)
.setOnAppBarCartClick(onCartClick);
} }
); );
} }

@ -0,0 +1,146 @@
import 'package:diplomaticquarterapp/core/viewModels/packages_offers/PackagesOffersViewModel.dart';
import 'package:diplomaticquarterapp/pages/base/base_view.dart';
import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_svg/svg.dart';
dynamic languageID;
class PackageOrderCompletedPage extends StatelessWidget{
double buttonHeight;
double buttonWidth;
Widget icon;
String heading;
String title;
String subTitle;
String actionTitle;
PackageOrderCompletedPage({this.buttonWidth, this.buttonHeight, @required this.heading, @required this.title, @required this.subTitle, this.actionTitle });
@override
Widget build(BuildContext context) {
assert((heading != null || title != null || subTitle != null), "Data missing in properties");
buttonWidth = buttonWidth ?? MediaQuery.of(context).size.width/2;
buttonHeight = buttonHeight ?? 40;
actionTitle = actionTitle ?? TranslationBase.of(context).done;
return BaseView<PackagesViewModel>(
allowAny: true,
onModelReady: (model){},
builder: (_, model, wi){
return Container(
color: Colors.white,
child: Padding(
padding: const EdgeInsets.all(15),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AspectRatio(
aspectRatio: 1.2/1,
child:
iconWidget(context),
),
headingWidget(context),
AspectRatio(
aspectRatio: 1/1,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
titleWidget(context),
SizedBox(height: 20,),
subTitleWidget(context),
SizedBox(height: 50,),
actionWidget(context)
],
),
),
)
],
),
),
);
}
);
}
Widget iconWidget(BuildContext context){
return Padding(
padding: const EdgeInsets.all(50),
child: icon ?? SvgPicture.asset(
"assets/images/svg/success.svg",
semanticsLabel: 'icon'
),
);
}
Widget headingWidget(BuildContext context) => Text(
heading,
textAlign: TextAlign.center,
maxLines: 1,
style: TextStyle(
color: Theme.of(context).primaryColor,
fontSize: 35.0,
fontWeight: FontWeight.bold,
letterSpacing: 0.9
)
);
Widget titleWidget(BuildContext context) => Text(
title,
textAlign: TextAlign.center,
maxLines: 2,
style: TextStyle(
color: Theme.of(context).primaryColor,
fontSize: 25.0,
fontWeight: FontWeight.w200,
letterSpacing: 0.9
)
);
Widget subTitleWidget(BuildContext context) => Text(
subTitle,
textAlign: TextAlign.center,
maxLines: 2,
style: TextStyle(
color: Theme.of(context).primaryColor,
fontSize: 15.0,
fontWeight: FontWeight.normal,
letterSpacing: 0.9
)
);
Widget actionWidget(BuildContext context) => Container(
height: buttonHeight,
width: buttonWidth,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
shape:RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(buttonHeight/2),
)
),
child: Text(
actionTitle,
style: TextStyle(
color: Colors.white,
fontSize: 18.0,
fontWeight: FontWeight.normal,
)
),
onPressed: (){
Navigator.of(context).pop();
},
),
);
}

@ -12,6 +12,7 @@ import 'package:diplomaticquarterapp/pages/login/login.dart';
import 'package:diplomaticquarterapp/pages/login/register.dart'; import 'package:diplomaticquarterapp/pages/login/register.dart';
import 'package:diplomaticquarterapp/pages/packages_offers/OfferAndPackagesCartPage.dart'; import 'package:diplomaticquarterapp/pages/packages_offers/OfferAndPackagesCartPage.dart';
import 'package:diplomaticquarterapp/pages/packages_offers/OfferAndPackagesPage.dart'; import 'package:diplomaticquarterapp/pages/packages_offers/OfferAndPackagesPage.dart';
import 'package:diplomaticquarterapp/pages/packages_offers/PackageOrderCompletedPage.dart';
import 'package:diplomaticquarterapp/pages/settings/settings.dart'; import 'package:diplomaticquarterapp/pages/settings/settings.dart';
import 'package:diplomaticquarterapp/pages/symptom-checker/info.dart'; import 'package:diplomaticquarterapp/pages/symptom-checker/info.dart';
import 'package:diplomaticquarterapp/pages/symptom-checker/select-gender.dart'; import 'package:diplomaticquarterapp/pages/symptom-checker/select-gender.dart';
@ -39,6 +40,7 @@ const String SELECT_GENDER = 'select-gender';
const String SETTINGS = 'settings'; const String SETTINGS = 'settings';
const String PACKAGES_OFFERS = 'packages-offers'; const String PACKAGES_OFFERS = 'packages-offers';
const String PACKAGES_OFFERS_CART = 'packages-offers-cart'; const String PACKAGES_OFFERS_CART = 'packages-offers-cart';
const String PACKAGES_ORDER_COMPLETED = 'packages-offers-cart';
var routes = { var routes = {
SPLASH: (_) => SplashScreen(), SPLASH: (_) => SplashScreen(),
@ -60,4 +62,5 @@ var routes = {
SETTINGS: (_) => Settings(), SETTINGS: (_) => Settings(),
PACKAGES_OFFERS: (_) => PackagesHomePage(), PACKAGES_OFFERS: (_) => PackagesHomePage(),
PACKAGES_OFFERS_CART: (_) => PackagesCartPage(), PACKAGES_OFFERS_CART: (_) => PackagesCartPage(),
PACKAGES_ORDER_COMPLETED: (_) => PackageOrderCompletedPage(),
}; };

@ -0,0 +1,347 @@
import 'dart:math';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
enum TextFieldInertiaDirection {
left,
right,
}
Interval _getInternalInterval(
double start,
double end,
double externalStart,
double externalEnd, [
Curve curve = Curves.linear,
]) {
return Interval(
start + (end - start) * externalStart,
start + (end - start) * externalEnd,
curve: curve,
);
}
class AnimatedTextFormField extends StatefulWidget {
AnimatedTextFormField({
Key key,
this.interval = const Interval(0.0, 1.0),
@required this.width,
this.loadingController,
this.inertiaController,
this.inertiaDirection,
this.enabled = true,
this.labelText,
this.prefixIcon,
this.suffixIcon,
this.keyboardType,
this.textInputAction,
this.obscureText = false,
this.controller,
this.focusNode,
this.validator,
this.onFieldSubmitted,
this.onSaved,
}) : assert((inertiaController == null && inertiaDirection == null) ||
(inertiaController != null && inertiaDirection != null)),
super(key: key);
final Interval interval;
final AnimationController loadingController;
final AnimationController inertiaController;
final double width;
final bool enabled;
final String labelText;
final Widget prefixIcon;
final Widget suffixIcon;
final TextInputType keyboardType;
final TextInputAction textInputAction;
final bool obscureText;
final TextEditingController controller;
final FocusNode focusNode;
final FormFieldValidator<String> validator;
final ValueChanged<String> onFieldSubmitted;
final FormFieldSetter<String> onSaved;
final TextFieldInertiaDirection inertiaDirection;
@override
_AnimatedTextFormFieldState createState() => _AnimatedTextFormFieldState();
}
class _AnimatedTextFormFieldState extends State<AnimatedTextFormField> {
Animation<double> scaleAnimation;
Animation<double> sizeAnimation;
Animation<double> suffixIconOpacityAnimation;
Animation<double> fieldTranslateAnimation;
Animation<double> iconRotationAnimation;
Animation<double> iconTranslateAnimation;
@override
void initState() {
super.initState();
widget.inertiaController?.addStatusListener(handleAnimationStatus);
final interval = widget.interval;
final loadingController = widget.loadingController;
if (loadingController != null) {
scaleAnimation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(CurvedAnimation(
parent: loadingController,
curve: _getInternalInterval(
0, .2, interval.begin, interval.end, Curves.easeOutBack),
));
suffixIconOpacityAnimation =
Tween<double>(begin: 0.0, end: 1.0).animate(CurvedAnimation(
parent: loadingController,
curve: _getInternalInterval(.65, 1.0, interval.begin, interval.end),
));
_updateSizeAnimation();
}
final inertiaController = widget.inertiaController;
final inertiaDirection = widget.inertiaDirection;
final sign = inertiaDirection == TextFieldInertiaDirection.right ? 1 : -1;
if (inertiaController != null) {
fieldTranslateAnimation = Tween<double>(
begin: 0.0,
end: sign * 15.0,
).animate(CurvedAnimation(
parent: inertiaController,
curve: Interval(0, .5, curve: Curves.easeOut),
reverseCurve: Curves.easeIn,
));
iconRotationAnimation =
Tween<double>(begin: 0.0, end: sign * pi / 12 /* ~15deg */)
.animate(CurvedAnimation(
parent: inertiaController,
curve: Interval(.5, 1.0, curve: Curves.easeOut),
reverseCurve: Curves.easeIn,
));
iconTranslateAnimation =
Tween<double>(begin: 0.0, end: 8.0).animate(CurvedAnimation(
parent: inertiaController,
curve: Interval(.5, 1.0, curve: Curves.easeOut),
reverseCurve: Curves.easeIn,
));
}
}
void _updateSizeAnimation() {
final interval = widget.interval;
final loadingController = widget.loadingController;
sizeAnimation = Tween<double>(
begin: 48.0,
end: widget.width,
).animate(CurvedAnimation(
parent: loadingController,
curve: _getInternalInterval(
.2, 1.0, interval.begin, interval.end, Curves.linearToEaseOut),
reverseCurve: Curves.easeInExpo,
));
}
@override
void didUpdateWidget(AnimatedTextFormField oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.width != widget.width) {
_updateSizeAnimation();
}
}
@override
dispose() {
widget.inertiaController?.removeStatusListener(handleAnimationStatus);
super.dispose();
}
void handleAnimationStatus(status) {
if (status == AnimationStatus.completed) {
widget.inertiaController?.reverse();
}
}
Widget _buildInertiaAnimation(Widget child) {
if (widget.inertiaController == null) {
return child;
}
return AnimatedBuilder(
animation: iconTranslateAnimation,
builder: (context, child) => Transform(
alignment: Alignment.center,
transform: Matrix4.identity()
..translate(iconTranslateAnimation.value)
..rotateZ(iconRotationAnimation.value),
child: child,
),
child: child,
);
}
InputDecoration _getInputDecoration(ThemeData theme) {
return InputDecoration(
contentPadding: EdgeInsets.fromLTRB(0, 0, 0, 0),
border: OutlineInputBorder(
borderRadius: new BorderRadius.circular(10.0),
borderSide: new BorderSide(),
),
labelText: widget.labelText,
prefixIcon: _buildInertiaAnimation(widget.prefixIcon),
suffixIcon: _buildInertiaAnimation(widget.loadingController != null
? FadeTransition(
opacity: suffixIconOpacityAnimation,
child: widget.suffixIcon,
)
: widget.suffixIcon),
);
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
Widget textField = TextFormField(
controller: widget.controller,
focusNode: widget.focusNode,
decoration: _getInputDecoration(theme),
keyboardType: widget.keyboardType,
textInputAction: widget.textInputAction,
obscureText: widget.obscureText,
onFieldSubmitted: widget.onFieldSubmitted,
onSaved: widget.onSaved,
validator: widget.validator,
enabled: widget.enabled,
);
if (widget.loadingController != null) {
textField = ScaleTransition(
scale: scaleAnimation,
child: AnimatedBuilder(
animation: sizeAnimation,
builder: (context, child) => ConstrainedBox(
constraints: BoxConstraints.tightFor(width: sizeAnimation.value),
child: child,
),
child: textField,
),
);
}
if (widget.inertiaController != null) {
textField = AnimatedBuilder(
animation: fieldTranslateAnimation,
builder: (context, child) => Transform.translate(
offset: Offset(fieldTranslateAnimation.value, 0),
child: child,
),
child: textField,
);
}
return textField;
}
}
class AnimatedPasswordTextFormField extends StatefulWidget {
AnimatedPasswordTextFormField({
Key key,
this.interval = const Interval(0.0, 1.0),
@required this.animatedWidth,
this.loadingController,
this.inertiaController,
this.inertiaDirection,
this.enabled = true,
this.labelText,
this.keyboardType,
this.textInputAction,
this.controller,
this.focusNode,
this.validator,
this.onFieldSubmitted,
this.onSaved,
}) : assert((inertiaController == null && inertiaDirection == null) ||
(inertiaController != null && inertiaDirection != null)),
super(key: key);
final Interval interval;
final AnimationController loadingController;
final AnimationController inertiaController;
final double animatedWidth;
final bool enabled;
final String labelText;
final TextInputType keyboardType;
final TextInputAction textInputAction;
final TextEditingController controller;
final FocusNode focusNode;
final FormFieldValidator<String> validator;
final ValueChanged<String> onFieldSubmitted;
final FormFieldSetter<String> onSaved;
final TextFieldInertiaDirection inertiaDirection;
@override
_AnimatedPasswordTextFormFieldState createState() =>
_AnimatedPasswordTextFormFieldState();
}
class _AnimatedPasswordTextFormFieldState
extends State<AnimatedPasswordTextFormField> {
var _obscureText = true;
@override
Widget build(BuildContext context) {
return AnimatedTextFormField(
interval: widget.interval,
loadingController: widget.loadingController,
inertiaController: widget.inertiaController,
width: widget.animatedWidth,
enabled: widget.enabled,
labelText: widget.labelText,
prefixIcon: Icon(Icons.lock, size: 20),
suffixIcon: GestureDetector(
onTap: () => setState(() => _obscureText = !_obscureText),
dragStartBehavior: DragStartBehavior.down,
child: AnimatedCrossFade(
duration: const Duration(milliseconds: 250),
firstCurve: Curves.easeInOutSine,
secondCurve: Curves.easeInOutSine,
alignment: Alignment.center,
layoutBuilder: (Widget topChild, _, Widget bottomChild, __) {
return Stack(
alignment: Alignment.center,
children: <Widget>[bottomChild, topChild],
);
},
firstChild: Icon(
Icons.visibility,
size: 25.0,
semanticLabel: 'show password',
),
secondChild: Icon(
Icons.visibility_off,
size: 25.0,
semanticLabel: 'hide password',
),
crossFadeState: _obscureText
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
),
),
obscureText: _obscureText,
keyboardType: widget.keyboardType,
textInputAction: widget.textInputAction,
controller: widget.controller,
focusNode: widget.focusNode,
validator: widget.validator,
onFieldSubmitted: widget.onFieldSubmitted,
onSaved: widget.onSaved,
inertiaDirection: widget.inertiaDirection,
);
}
}

@ -0,0 +1,465 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:math';
class AnimatedButton extends StatefulWidget {
AnimatedButton({
Key key,
@required this.text,
@required this.onPressed,
@required this.controller,
this.textColor,
this.loadingColor,
this.color,
}) : super(key: key);
final String text;
final Color color;
final Color textColor;
final Color loadingColor;
final Function onPressed;
final AnimationController controller;
@override
_AnimatedButtonState createState() => _AnimatedButtonState();
}
class _AnimatedButtonState extends State<AnimatedButton>
with SingleTickerProviderStateMixin {
Animation<double> _sizeAnimation;
Animation<double> _textOpacityAnimation;
Animation<double> _buttonOpacityAnimation;
Animation<double> _ringThicknessAnimation;
Animation<double> _ringOpacityAnimation;
Animation<Color> _colorAnimation;
var _isLoading = false;
var _hover = false;
var _width = 120.0;
Color _color;
Color _loadingColor;
static const _height = 40.0;
static const _loadingCircleRadius = _height / 2;
static const _loadingCircleThickness = 4.0;
@override
void initState() {
super.initState();
_textOpacityAnimation = Tween<double>(begin: 1.0, end: 0.0).animate(
CurvedAnimation(
parent: widget.controller,
curve: Interval(0.0, .25),
),
);
// _colorAnimation
// _width, _sizeAnimation
_buttonOpacityAnimation =
Tween<double>(begin: 1.0, end: 0.0).animate(CurvedAnimation(
parent: widget.controller,
curve: Threshold(.65),
));
_ringThicknessAnimation =
Tween<double>(begin: _loadingCircleRadius, end: _loadingCircleThickness)
.animate(CurvedAnimation(
parent: widget.controller,
curve: Interval(.65, .85),
));
_ringOpacityAnimation =
Tween<double>(begin: 1.0, end: 0.0).animate(CurvedAnimation(
parent: widget.controller,
curve: Interval(.85, 1.0),
));
widget.controller.addStatusListener(handleStatusChanged);
}
@override
void didChangeDependencies() {
_updateColorAnimation();
_updateWidth();
super.didChangeDependencies();
}
void _updateColorAnimation() {
final theme = Theme.of(context);
final buttonTheme = theme.floatingActionButtonTheme;
_color = widget.color ?? buttonTheme.backgroundColor;
_loadingColor = widget.loadingColor ?? theme.accentColor;
_colorAnimation = ColorTween(
begin: _color,
end: _loadingColor,
).animate(
CurvedAnimation(
parent: widget.controller,
curve: const Interval(0.0, .65, curve: Curves.fastOutSlowIn),
),
);
}
@override
void didUpdateWidget(AnimatedButton oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.color != widget.color ||
oldWidget.loadingColor != widget.loadingColor) {
_updateColorAnimation();
}
if (oldWidget.text != widget.text) {
_updateWidth();
}
}
@override
void dispose() {
super.dispose();
widget.controller.removeStatusListener(handleStatusChanged);
}
void handleStatusChanged(status) {
if (status == AnimationStatus.forward) {
setState(() => _isLoading = true);
}
if (status == AnimationStatus.dismissed) {
setState(() => _isLoading = false);
}
}
/// sets width and size animation
void _updateWidth() {
final theme = Theme.of(context);
final fontSize = theme.textTheme.button.fontSize;
final renderParagraph = RenderParagraph(
TextSpan(
text: widget.text,
style: TextStyle(
fontSize: fontSize,
fontWeight: theme.textTheme.button.fontWeight,
letterSpacing: theme.textTheme.button.letterSpacing,
),
),
textDirection: TextDirection.ltr,
maxLines: 1,
);
renderParagraph.layout(BoxConstraints(minWidth: 120.0));
// text width based on fontSize, plus 45.0 for padding
var textWidth =
renderParagraph.getMinIntrinsicWidth(fontSize).ceilToDouble() + 45.0;
// button width is min 120.0 and max 240.0
_width = textWidth > 120.0 && textWidth < 240.0
? textWidth
: textWidth >= 240.0 ? 240.0 : 120.0;
_sizeAnimation = Tween<double>(begin: 1.0, end: _height / _width)
.animate(CurvedAnimation(
parent: widget.controller,
curve: Interval(0.0, .65, curve: Curves.fastOutSlowIn),
));
}
Widget _buildButtonText(ThemeData theme) {
return FadeTransition(
opacity: _textOpacityAnimation,
child: AnimatedText(
text: widget.text,
style: TextStyle(color: widget.textColor ?? Colors.white),
),
);
}
Widget _buildButton(ThemeData theme) {
final buttonTheme = theme.floatingActionButtonTheme;
return FadeTransition(
opacity: _buttonOpacityAnimation,
child: AnimatedContainer(
duration: Duration(milliseconds: 300),
child: AnimatedBuilder(
animation: _colorAnimation,
builder: (context, child) => Material(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(_height/2)
),
color: _colorAnimation.value,
child: child,
shadowColor: _color,
elevation: !_isLoading
? (_hover ? buttonTheme.highlightElevation : buttonTheme.elevation)
: 0,
),
child: InkWell(
onTap: !_isLoading ? widget.onPressed : null,
splashColor: buttonTheme.splashColor,
customBorder: buttonTheme.shape,
onHighlightChanged: (value) => setState(() => _hover = value),
child: SizeTransition(
sizeFactor: _sizeAnimation,
axis: Axis.horizontal,
child: Container(
width: _width,
height: _height,
alignment: Alignment.center,
child: _buildButtonText(theme),
),
),
),
),
),
);
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Stack(
alignment: Alignment.center,
children: <Widget>[
FadeTransition(
opacity: _ringOpacityAnimation,
child: AnimatedBuilder(
animation: _ringThicknessAnimation,
builder: (context, child) => Ring(
color: widget.loadingColor,
size: _height,
thickness: _ringThicknessAnimation.value,
),
),
),
if (_isLoading)
SizedBox(
width: _height - _loadingCircleThickness,
height: _height - _loadingCircleThickness,
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(widget.loadingColor),
// backgroundColor: Colors.red,
strokeWidth: _loadingCircleThickness,
),
),
_buildButton(theme),
],
);
}
}
class Ring extends StatelessWidget {
Ring({
Key key,
this.color,
this.size = 40.0,
this.thickness = 2.0,
this.value = 1.0,
}) : assert(size - thickness > 0),
assert(thickness >= 0),
super(key: key);
final Color color;
final double size;
final double thickness;
final double value;
@override
Widget build(BuildContext context) {
return SizedBox(
width: size - thickness,
height: size - thickness,
child: thickness == 0
? null
: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(color),
strokeWidth: thickness,
value: value,
),
);
}
}
enum AnimatedTextRotation { up, down }
/// https://medium.com/flutter-community/flutter-challenge-3d-bottom-navigation-bar-48952a5fd996
class AnimatedText extends StatefulWidget {
AnimatedText({
Key key,
@required this.text,
this.style,
this.textRotation = AnimatedTextRotation.up,
}) : super(key: key);
final String text;
final TextStyle style;
final AnimatedTextRotation textRotation;
@override
_AnimatedTextState createState() => _AnimatedTextState();
}
class _AnimatedTextState extends State<AnimatedText>
with SingleTickerProviderStateMixin {
var _newText = '';
var _oldText = '';
var _layoutHeight = 0.0;
final _textKey = GlobalKey();
Animation<double> _animation;
AnimationController _controller;
double get radius => _layoutHeight / 2;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 500),
);
_animation = Tween<double>(begin: 0.0, end: pi / 2).animate(CurvedAnimation(
parent: _controller,
curve: Curves.easeOutBack,
));
_oldText = widget.text;
WidgetsBinding.instance.addPostFrameCallback((_) {
setState(() => _layoutHeight = getWidgetSize(_textKey)?.height);
});
}
@override
void didUpdateWidget(AnimatedText oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.text != oldWidget.text) {
_oldText = oldWidget.text;
_newText = widget.text;
_controller.forward().then((_) {
setState(() {
final t = _oldText;
_oldText = _newText;
_newText = t;
});
_controller.reset();
});
}
}
@override
void dispose() {
super.dispose();
_controller.dispose();
}
Matrix4 get _matrix {
// Fix: The text is not centered after applying perspective effect in the web build. Idk why
if (kIsWeb) {
return Matrix4.identity();
}
return Matrix4.identity()..setEntry(3, 2, .006);
}
Matrix4 _getFrontSideUp(double value) {
return _matrix
..translate(
0.0,
-radius * sin(_animation.value),
-radius * cos(_animation.value),
)
..rotateX(-_animation.value); // 0 -> -pi/2
}
Matrix4 _getBackSideUp(double value) {
return _matrix
..translate(
0.0,
radius * cos(_animation.value),
-radius * sin(_animation.value),
)
..rotateX((pi / 2) - _animation.value); // pi/2 -> 0
}
Matrix4 _getFrontSideDown(double value) {
return _matrix
..translate(
0.0,
radius * sin(_animation.value),
-radius * cos(_animation.value),
)
..rotateX(_animation.value); // 0 -> pi/2
}
Matrix4 _getBackSideDown(double value) {
return _matrix
..translate(
0.0,
-radius * cos(_animation.value),
-radius * sin(_animation.value),
)
..rotateX(_animation.value - pi / 2); // -pi/2 -> 0
}
@override
Widget build(BuildContext context) {
final rollUp = widget.textRotation == AnimatedTextRotation.up;
final oldText = Text(
_oldText,
key: _textKey,
style: widget.style,
overflow: TextOverflow.visible,
softWrap: false,
);
final newText = Text(
_newText,
style: widget.style,
overflow: TextOverflow.visible,
softWrap: false,
);
return AnimatedBuilder(
animation: _animation,
builder: (context, child) => Stack(
alignment: Alignment.center,
children: <Widget>[
if (_animation.value <= toRadian(85))
Transform(
alignment: Alignment.center,
transform: rollUp
? _getFrontSideUp(_animation.value)
: _getFrontSideDown(_animation.value),
child: oldText,
),
if (_animation.value >= toRadian(5))
Transform(
alignment: Alignment.center,
transform: rollUp
? _getBackSideUp(_animation.value)
: _getBackSideDown(_animation.value),
child: newText,
),
],
),
);
}
// Helpers
double toRadian(double degree) => degree * pi / 180;
double lerp(double start, double end, double percent) => (start + percent * (end - start));
Size getWidgetSize(GlobalKey key) {
final RenderBox renderBox = key.currentContext?.findRenderObject();
return renderBox?.size;
}
}

@ -0,0 +1,343 @@
import 'dart:math';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
enum TextFieldInertiaDirection {
left,
right,
}
Interval _getInternalInterval(
double start,
double end,
double externalStart,
double externalEnd, [
Curve curve = Curves.linear,
]) {
return Interval(
start + (end - start) * externalStart,
start + (end - start) * externalEnd,
curve: curve,
);
}
class AnimatedTextFormField extends StatefulWidget {
AnimatedTextFormField({
Key key,
this.interval = const Interval(0.0, 1.0),
@required this.width,
this.loadingController,
this.inertiaController,
this.inertiaDirection,
this.enabled = true,
this.labelText,
this.prefixIcon,
this.suffixIcon,
this.keyboardType,
this.textInputAction,
this.obscureText = false,
this.controller,
this.focusNode,
this.validator,
this.onFieldSubmitted,
this.onSaved,
}) : assert((inertiaController == null && inertiaDirection == null) ||
(inertiaController != null && inertiaDirection != null)),
super(key: key);
final Interval interval;
final AnimationController loadingController;
final AnimationController inertiaController;
final double width;
final bool enabled;
final String labelText;
final Widget prefixIcon;
final Widget suffixIcon;
final TextInputType keyboardType;
final TextInputAction textInputAction;
final bool obscureText;
final TextEditingController controller;
final FocusNode focusNode;
final FormFieldValidator<String> validator;
final ValueChanged<String> onFieldSubmitted;
final FormFieldSetter<String> onSaved;
final TextFieldInertiaDirection inertiaDirection;
@override
_AnimatedTextFormFieldState createState() => _AnimatedTextFormFieldState();
}
class _AnimatedTextFormFieldState extends State<AnimatedTextFormField> {
Animation<double> scaleAnimation;
Animation<double> sizeAnimation;
Animation<double> suffixIconOpacityAnimation;
Animation<double> fieldTranslateAnimation;
Animation<double> iconRotationAnimation;
Animation<double> iconTranslateAnimation;
@override
void initState() {
super.initState();
widget.inertiaController?.addStatusListener(handleAnimationStatus);
final interval = widget.interval;
final loadingController = widget.loadingController;
if (loadingController != null) {
scaleAnimation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(CurvedAnimation(
parent: loadingController,
curve: _getInternalInterval(
0, .2, interval.begin, interval.end, Curves.easeOutBack),
));
suffixIconOpacityAnimation =
Tween<double>(begin: 0.0, end: 1.0).animate(CurvedAnimation(
parent: loadingController,
curve: _getInternalInterval(.65, 1.0, interval.begin, interval.end),
));
_updateSizeAnimation();
}
final inertiaController = widget.inertiaController;
final inertiaDirection = widget.inertiaDirection;
final sign = inertiaDirection == TextFieldInertiaDirection.right ? 1 : -1;
if (inertiaController != null) {
fieldTranslateAnimation = Tween<double>(
begin: 0.0,
end: sign * 15.0,
).animate(CurvedAnimation(
parent: inertiaController,
curve: Interval(0, .5, curve: Curves.easeOut),
reverseCurve: Curves.easeIn,
));
iconRotationAnimation =
Tween<double>(begin: 0.0, end: sign * pi / 12 /* ~15deg */)
.animate(CurvedAnimation(
parent: inertiaController,
curve: Interval(.5, 1.0, curve: Curves.easeOut),
reverseCurve: Curves.easeIn,
));
iconTranslateAnimation =
Tween<double>(begin: 0.0, end: 8.0).animate(CurvedAnimation(
parent: inertiaController,
curve: Interval(.5, 1.0, curve: Curves.easeOut),
reverseCurve: Curves.easeIn,
));
}
}
void _updateSizeAnimation() {
final interval = widget.interval;
final loadingController = widget.loadingController;
sizeAnimation = Tween<double>(
begin: 48.0,
end: widget.width,
).animate(CurvedAnimation(
parent: loadingController,
curve: _getInternalInterval(
.2, 1.0, interval.begin, interval.end, Curves.linearToEaseOut),
reverseCurve: Curves.easeInExpo,
));
}
@override
void didUpdateWidget(AnimatedTextFormField oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.width != widget.width) {
_updateSizeAnimation();
}
}
@override
dispose() {
widget.inertiaController?.removeStatusListener(handleAnimationStatus);
super.dispose();
}
void handleAnimationStatus(status) {
if (status == AnimationStatus.completed) {
widget.inertiaController?.reverse();
}
}
Widget _buildInertiaAnimation(Widget child) {
if (widget.inertiaController == null) {
return child;
}
return AnimatedBuilder(
animation: iconTranslateAnimation,
builder: (context, child) => Transform(
alignment: Alignment.center,
transform: Matrix4.identity()
..translate(iconTranslateAnimation.value)
..rotateZ(iconRotationAnimation.value),
child: child,
),
child: child,
);
}
InputDecoration _getInputDecoration(ThemeData theme) {
return InputDecoration(
labelText: widget.labelText,
prefixIcon: _buildInertiaAnimation(widget.prefixIcon),
suffixIcon: _buildInertiaAnimation(widget.loadingController != null
? FadeTransition(
opacity: suffixIconOpacityAnimation,
child: widget.suffixIcon,
)
: widget.suffixIcon),
);
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
Widget textField = TextFormField(
controller: widget.controller,
focusNode: widget.focusNode,
decoration: _getInputDecoration(theme),
keyboardType: widget.keyboardType,
textInputAction: widget.textInputAction,
obscureText: widget.obscureText,
onFieldSubmitted: widget.onFieldSubmitted,
onSaved: widget.onSaved,
validator: widget.validator,
enabled: widget.enabled,
);
if (widget.loadingController != null) {
textField = ScaleTransition(
scale: scaleAnimation,
child: AnimatedBuilder(
animation: sizeAnimation,
builder: (context, child) => ConstrainedBox(
constraints: BoxConstraints.tightFor(width: sizeAnimation.value),
child: child,
),
child: textField,
),
);
}
if (widget.inertiaController != null) {
textField = AnimatedBuilder(
animation: fieldTranslateAnimation,
builder: (context, child) => Transform.translate(
offset: Offset(fieldTranslateAnimation.value, 0),
child: child,
),
child: textField,
);
}
return textField;
}
}
class AnimatedPasswordTextFormField extends StatefulWidget {
AnimatedPasswordTextFormField({
Key key,
this.interval = const Interval(0.0, 1.0),
@required this.animatedWidth,
this.loadingController,
this.inertiaController,
this.inertiaDirection,
this.enabled = true,
this.labelText,
this.keyboardType,
this.textInputAction,
this.controller,
this.focusNode,
this.validator,
this.onFieldSubmitted,
this.onSaved,
}) : assert((inertiaController == null && inertiaDirection == null) ||
(inertiaController != null && inertiaDirection != null)),
super(key: key);
final Interval interval;
final AnimationController loadingController;
final AnimationController inertiaController;
final double animatedWidth;
final bool enabled;
final String labelText;
final TextInputType keyboardType;
final TextInputAction textInputAction;
final TextEditingController controller;
final FocusNode focusNode;
final FormFieldValidator<String> validator;
final ValueChanged<String> onFieldSubmitted;
final FormFieldSetter<String> onSaved;
final TextFieldInertiaDirection inertiaDirection;
@override
_AnimatedPasswordTextFormFieldState createState() =>
_AnimatedPasswordTextFormFieldState();
}
class _AnimatedPasswordTextFormFieldState
extends State<AnimatedPasswordTextFormField> {
var _obscureText = true;
@override
Widget build(BuildContext context) {
return AnimatedTextFormField(
interval: widget.interval,
loadingController: widget.loadingController,
inertiaController: widget.inertiaController,
width: widget.animatedWidth,
enabled: widget.enabled,
labelText: widget.labelText,
prefixIcon: Icon(FontAwesomeIcons.lock, size: 20),
suffixIcon: GestureDetector(
onTap: () => setState(() => _obscureText = !_obscureText),
dragStartBehavior: DragStartBehavior.down,
child: AnimatedCrossFade(
duration: const Duration(milliseconds: 250),
firstCurve: Curves.easeInOutSine,
secondCurve: Curves.easeInOutSine,
alignment: Alignment.center,
layoutBuilder: (Widget topChild, _, Widget bottomChild, __) {
return Stack(
alignment: Alignment.center,
children: <Widget>[bottomChild, topChild],
);
},
firstChild: Icon(
Icons.visibility,
size: 25.0,
semanticLabel: 'show password',
),
secondChild: Icon(
Icons.visibility_off,
size: 25.0,
semanticLabel: 'hide password',
),
crossFadeState: _obscureText
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
),
),
obscureText: _obscureText,
keyboardType: widget.keyboardType,
textInputAction: widget.textInputAction,
controller: widget.controller,
focusNode: widget.focusNode,
validator: widget.validator,
onFieldSubmitted: widget.onFieldSubmitted,
onSaved: widget.onSaved,
inertiaDirection: widget.inertiaDirection,
);
}
}

@ -1,13 +1,26 @@
import 'dart:convert'; import 'dart:convert';
import 'package:diplomaticquarterapp/config/config.dart';
import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; import 'package:diplomaticquarterapp/config/shared_pref_kay.dart';
import 'package:diplomaticquarterapp/models/Appointments/AppoimentAllHistoryResultList.dart'; import 'package:diplomaticquarterapp/models/Appointments/AppoimentAllHistoryResultList.dart';
import 'package:diplomaticquarterapp/models/Authentication/authenticated_user.dart'; import 'package:diplomaticquarterapp/models/Authentication/authenticated_user.dart';
import 'package:diplomaticquarterapp/services/authentication/auth_provider.dart'; import 'package:diplomaticquarterapp/services/authentication/auth_provider.dart';
import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart';
enum _PAYMENT_TYPE{PACKAGES, PHARMACY, PATIENT}
var _InAppBrowserOptions = InAppBrowserClassOptions(
inAppWebViewGroupOptions: InAppWebViewGroupOptions(crossPlatform: InAppWebViewOptions(useShouldOverrideUrlLoading: true)),
crossPlatform: InAppBrowserOptions(hideUrlBar: true),
ios: IOSInAppBrowserOptions(toolbarBottom: false,)
);
class MyInAppBrowser extends InAppBrowser { class MyInAppBrowser extends InAppBrowser {
_PAYMENT_TYPE paymentType;
static String SERVICE_URL = static String SERVICE_URL =
'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx'; // Payfort Payment Gateway URL UAT 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx'; // Payfort Payment Gateway URL UAT
@ -20,6 +33,11 @@ class MyInAppBrowser extends InAppBrowser {
// static String PREAUTH_SERVICE_URL = // static String PREAUTH_SERVICE_URL =
// 'https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx'; //Payfort PreAuth Payment Gateway URL Live Store // 'https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx'; //Payfort PreAuth Payment Gateway URL Live Store
// Packages
static String PACKAGES_REQUEST_PAYMENT_URL = '$EXA_CART_API_BASE_URL/checkout/OpcCompleteRedirectionPayment1';
static String PACKAGES_PAYMENT_SUCCESS_URL = '$EXA_CART_API_BASE_URL/Checkout/MobilePaymentSuccess';
static String PACKAGES_PAYMENT_FAIL_URL = '$EXA_CART_API_BASE_URL/Checkout/MobilePaymentFailed';
static List<String> successURLS = [ static List<String> successURLS = [
'success', 'success',
'PayFortResponse', 'PayFortResponse',
@ -30,6 +48,7 @@ class MyInAppBrowser extends InAppBrowser {
final Function onExitCallback; final Function onExitCallback;
final Function onLoadStartCallback; final Function onLoadStartCallback;
final BuildContext context;
AppSharedPreferences sharedPref = AppSharedPreferences(); AppSharedPreferences sharedPref = AppSharedPreferences();
AuthProvider authProvider = new AuthProvider(); AuthProvider authProvider = new AuthProvider();
@ -45,7 +64,7 @@ class MyInAppBrowser extends InAppBrowser {
static bool isPaymentDone = false; static bool isPaymentDone = false;
MyInAppBrowser({this.onExitCallback, this.appo, this.onLoadStartCallback}); MyInAppBrowser({this.onExitCallback, this.appo, this.onLoadStartCallback, this.context});
Future onBrowserCreated() async { Future onBrowserCreated() async {
print("\n\nBrowser Created!\n\n"); print("\n\nBrowser Created!\n\n");
@ -53,7 +72,8 @@ class MyInAppBrowser extends InAppBrowser {
@override @override
Future onLoadStart(String url) async { Future onLoadStart(String url) async {
onLoadStartCallback(url); if(onLoadStartCallback != null)
onLoadStartCallback(url);
} }
@override @override
@ -74,13 +94,20 @@ class MyInAppBrowser extends InAppBrowser {
@override @override
void onExit() { void onExit() {
print("\n\nBrowser closed!\n\n"); print("\n\nBrowser closed!\n\n");
onExitCallback(appo, isPaymentDone); if(onExitCallback != null)
onExitCallback(appo, isPaymentDone);
} }
@override @override
Future<ShouldOverrideUrlLoadingAction> shouldOverrideUrlLoading( Future<ShouldOverrideUrlLoadingAction> shouldOverrideUrlLoading(ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest) async {
ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest) async { var url = shouldOverrideUrlLoadingRequest.url;
print("\n\n override ${shouldOverrideUrlLoadingRequest.url}\n\n"); debugPrint("redirecting/overriding to: $url");
if(paymentType == _PAYMENT_TYPE.PACKAGES && [PACKAGES_PAYMENT_SUCCESS_URL,PACKAGES_PAYMENT_FAIL_URL].contains(url)){
isPaymentDone = (url == PACKAGES_PAYMENT_SUCCESS_URL);
close();
}
return ShouldOverrideUrlLoadingAction.ALLOW; return ShouldOverrideUrlLoadingAction.ALLOW;
} }
@ -106,6 +133,12 @@ class MyInAppBrowser extends InAppBrowser {
} }
} }
openPackagesPaymentBrowser({@required int customer_id, @required int order_id}){
paymentType = _PAYMENT_TYPE.PACKAGES;
var full_url = '$PACKAGES_REQUEST_PAYMENT_URL?customer_id=$customer_id&order_id=$order_id';
this.openUrl(url: full_url, options: _InAppBrowserOptions);
}
openPaymentBrowser( openPaymentBrowser(
double amount, double amount,
String orderDesc, String orderDesc,
@ -142,13 +175,15 @@ class MyInAppBrowser extends InAppBrowser {
clinicID, clinicID,
doctorID) doctorID)
.then((value) { .then((value) {
this.browser.openUrl(url: value);
paymentType = _PAYMENT_TYPE.PATIENT;
this.browser.openUrl(url: value, options: _InAppBrowserOptions);
}); });
} }
openBrowser(String url) { openBrowser(String url) {
this.browser = browser; this.browser = browser;
this.browser.openUrl(url: url); this.browser.openUrl(url: url, options: _InAppBrowserOptions);
} }
Future<String> generateURL( Future<String> generateURL(

@ -12,7 +12,7 @@ import 'package:flutter/material.dart';
bool wide = true; bool wide = true;
class PackagesCartItemCard extends StatefulWidget { class PackagesCartItemCard extends StatefulWidget {
final CartProductResponseModel itemModel; final PackagesCartItemsResponseModel itemModel;
final StepperCallbackFuture shouldStepperChangeApply ; final StepperCallbackFuture shouldStepperChangeApply ;
const PackagesCartItemCard( const PackagesCartItemCard(

@ -30,6 +30,7 @@ class PackagesItemCard extends StatefulWidget {
} }
class PackagesItemCardState extends State<PackagesItemCard> { class PackagesItemCardState extends State<PackagesItemCard> {
imageUrl() => widget.itemModel.images.isNotEmpty ? widget.itemModel.images.first.src : "https://wallpaperaccess.com/full/30103.jpg";
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -57,8 +58,7 @@ class PackagesItemCardState extends State<PackagesItemCard> {
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
child: Utils.loadNetworkImage( child: Utils.loadNetworkImage(
url: url: imageUrl(),
"https://wallpaperaccess.com/full/30103.jpg",
)), )),
)), )),
Text( Text(

@ -1,3 +1,4 @@
import 'package:badges/badges.dart';
import 'package:diplomaticquarterapp/config/config.dart'; import 'package:diplomaticquarterapp/config/config.dart';
import 'package:diplomaticquarterapp/config/size_config.dart'; import 'package:diplomaticquarterapp/config/size_config.dart';
import 'package:diplomaticquarterapp/config/size_config.dart'; import 'package:diplomaticquarterapp/config/size_config.dart';
@ -56,6 +57,7 @@ class AppScaffold extends StatelessWidget {
AuthenticatedUserObject authenticatedUserObject = AuthenticatedUserObject authenticatedUserObject =
locator<AuthenticatedUserObject>(); locator<AuthenticatedUserObject>();
AppBarWidget appBar;
AppScaffold( AppScaffold(
{@required this.body, {@required this.body,
this.appBarTitle = '', this.appBarTitle = '',
@ -92,7 +94,7 @@ class AppScaffold extends StatelessWidget {
backgroundColor: backgroundColor:
backgroundColor ?? Theme.of(context).scaffoldBackgroundColor, backgroundColor ?? Theme.of(context).scaffoldBackgroundColor,
appBar: isShowAppBar appBar: isShowAppBar
? AppBarWidget( ? appBar = AppBarWidget(
appBarTitle: appBarTitle, appBarTitle: appBarTitle,
appBarIcons: appBarIcons, appBarIcons: appBarIcons,
showHomeAppBarIcon: showHomeAppBarIcon, showHomeAppBarIcon: showHomeAppBarIcon,
@ -104,20 +106,23 @@ class AppScaffold extends StatelessWidget {
) )
: null, : null,
bottomSheet: bottomSheet, bottomSheet: bottomSheet,
body: (!Provider.of<ProjectViewModel>(context, listen: false).isLogin && body: SafeArea(
isShowDecPage) top: true, bottom: true,
? NotAutPage( child: (!Provider.of<ProjectViewModel>(context, listen: false).isLogin &&
title: title ?? appBarTitle, isShowDecPage)
description: description, ? NotAutPage(
infoList: infoList, title: title ?? appBarTitle,
imagesInfo: imagesInfo, description: description,
) infoList: infoList,
: baseViewModel != null imagesInfo: imagesInfo,
? NetworkBaseView( )
child: body, : baseViewModel != null
baseViewModel: baseViewModel, ? NetworkBaseView(
) child: body,
: body, baseViewModel: baseViewModel,
)
: body,
),
floatingActionButton: floatingActionButton, floatingActionButton: floatingActionButton,
); );
} }
@ -127,7 +132,7 @@ class AppScaffold extends StatelessWidget {
} }
} }
class AppBarWidget extends StatelessWidget with PreferredSizeWidget { class AppBarWidget extends StatefulWidget with PreferredSizeWidget {
final AuthenticatedUserObject authenticatedUserObject = final AuthenticatedUserObject authenticatedUserObject =
locator<AuthenticatedUserObject>(); locator<AuthenticatedUserObject>();
@ -140,6 +145,8 @@ class AppBarWidget extends StatelessWidget with PreferredSizeWidget {
final bool showOfferPackagesCart; final bool showOfferPackagesCart;
final bool isShowDecPage; final bool isShowDecPage;
Function(String) badgeUpdater;
AppBarWidget( AppBarWidget(
{this.appBarTitle, {this.appBarTitle,
this.showHomeAppBarIcon, this.showHomeAppBarIcon,
@ -150,23 +157,40 @@ class AppBarWidget extends StatelessWidget with PreferredSizeWidget {
this.showOfferPackagesCart = false, this.showOfferPackagesCart = false,
this.isShowDecPage = true}); this.isShowDecPage = true});
@override
State<StatefulWidget> createState() => AppBarWidgetState();
@override
Size get preferredSize => Size(double.maxFinite, 60);
}
class AppBarWidgetState extends State<AppBarWidget>{
String badgeText = "0";
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
widget.badgeUpdater = badgeUpdateBlock;
return buildAppBar(context); return buildAppBar(context);
} }
badgeUpdateBlock(String value){
setState(() {
badgeText = value;
});
}
Widget buildAppBar(BuildContext context) { Widget buildAppBar(BuildContext context) {
ProjectViewModel projectViewModel = Provider.of(context); ProjectViewModel projectViewModel = Provider.of(context);
return AppBar( return AppBar(
elevation: 0, elevation: 0,
backgroundColor: backgroundColor:
isPharmacy ? Colors.green : Theme.of(context).appBarTheme.color, widget.isPharmacy ? Colors.green : Theme.of(context).appBarTheme.color,
textTheme: TextTheme( textTheme: TextTheme(
headline6: TextStyle(color: Colors.white, fontWeight: FontWeight.bold), headline6: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
), ),
title: Text( title: Text(
authenticatedUserObject.isLogin || !isShowDecPage widget.authenticatedUserObject.isLogin || !widget.isShowDecPage
? appBarTitle.toUpperCase() ? widget.appBarTitle.toUpperCase()
: TranslationBase.of(context).serviceInformationTitle, : TranslationBase.of(context).serviceInformationTitle,
style: TextStyle( style: TextStyle(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
@ -179,18 +203,31 @@ class AppBarWidget extends StatelessWidget with PreferredSizeWidget {
), ),
centerTitle: true, centerTitle: true,
actions: <Widget>[ actions: <Widget>[
(isPharmacy && showPharmacyCart) (widget.isPharmacy && widget.showPharmacyCart)
? IconButton( ? IconButton(
icon: Icon(Icons.shopping_cart), icon: Badge(
badgeContent: Text(
badgeText
),
child: Icon(Icons.shopping_cart)
),
color: Colors.white, color: Colors.white,
onPressed: () { onPressed: () {
Navigator.of(context).popUntil(ModalRoute.withName('/')); Navigator.of(context).popUntil(ModalRoute.withName('/'));
}) })
: Container(), : Container(),
(isOfferPackages && showOfferPackagesCart) (widget.isOfferPackages && widget.showOfferPackagesCart)
? IconButton( ? IconButton(
icon: Icon(Icons.shopping_cart), icon: Badge(
position: BadgePosition.topStart(top: -15,start: -10),
badgeContent: Text(
badgeText,
style: TextStyle(fontSize: 9,color: Colors.white, fontWeight: FontWeight.normal),
),
child: Icon(Icons.shopping_cart)
),
color: Colors.white, color: Colors.white,
onPressed: () { onPressed: () {
// Cart Click Event // Cart Click Event
@ -200,7 +237,7 @@ class AppBarWidget extends StatelessWidget with PreferredSizeWidget {
}) })
: Container(), : Container(),
if (showHomeAppBarIcon) if (widget.showHomeAppBarIcon)
IconButton( IconButton(
icon: Icon(FontAwesomeIcons.home), icon: Icon(FontAwesomeIcons.home),
color: Colors.white, color: Colors.white,
@ -208,18 +245,16 @@ class AppBarWidget extends StatelessWidget with PreferredSizeWidget {
Navigator.pushAndRemoveUntil( Navigator.pushAndRemoveUntil(
context, context,
MaterialPageRoute(builder: (context) => LandingPage()), MaterialPageRoute(builder: (context) => LandingPage()),
(Route<dynamic> r) => false); (Route<dynamic> r) => false);
// Cart Click Event // Cart Click Event
if(_onCartClick != null) if(_onCartClick != null)
_onCartClick(); _onCartClick();
}, },
), ),
if (appBarIcons != null) ...appBarIcons if (widget.appBarIcons != null) ...widget.appBarIcons
], ],
); );
} }
@override
Size get preferredSize => Size(double.maxFinite, 60);
} }

Loading…
Cancel
Save