Packages And offers..

merge-requests/290/head
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">
<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">

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 PACKAGES_CATEGORIES = '/api/categories';
const PACKAGES_PRODUCTS = '/api/products';
const PACKAGES_SHOPPING_CART = '/api/shopping_cart_items';
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://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';
class CartProductResponseModel {
class PackagesCartItemsResponseModel {
int _quantity;
set quantity(int value) {
@ -19,7 +19,7 @@ class CartProductResponseModel {
PackagesResponseModel get product => _product;
int get id => _id;
CartProductResponseModel({
PackagesCartItemsResponseModel({
int quantity,
String shoppingCartType,
int productId,
@ -32,7 +32,7 @@ class CartProductResponseModel {
_id = id;
}
CartProductResponseModel.fromJson(dynamic json) {
PackagesCartItemsResponseModel.fromJson(dynamic json) {
_quantity = json["quantity"];
_shoppingCartType = json["shopping_cart_type"];
_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 {
List<dynamic> _shoppingCartItems;
List<PackagesCartItemsResponseModel> _shoppingCartItems;
dynamic _billingAddress;
dynamic _shippingAddress;
List<dynamic> _addresses;
List<Addresses> _addresses;
String _customerGuid;
dynamic _username;
String _email;
@ -24,13 +54,13 @@ class PackagesCustomerResponseModel {
String _lastActivityDateUtc;
int _registeredInStoreId;
bool _subscribedToNewsletter;
List<dynamic> _roleIds;
List<int> _roleIds;
int _id;
List<dynamic> get shoppingCartItems => _shoppingCartItems;
dynamic get billingAddress => _billingAddress;
dynamic get shippingAddress => _shippingAddress;
List<dynamic> get addresses => _addresses;
List<Addresses> get addresses => _addresses;
String get customerGuid => _customerGuid;
dynamic get username => _username;
String get email => _email;
@ -59,7 +89,7 @@ class PackagesCustomerResponseModel {
List<dynamic> shoppingCartItems,
dynamic billingAddress,
dynamic shippingAddress,
List<dynamic> addresses,
List<Addresses> addresses,
String customerGuid,
dynamic username,
String email,
@ -115,6 +145,12 @@ class PackagesCustomerResponseModel {
PackagesCustomerResponseModel.fromJson(dynamic json) {
_billingAddress = json["billing_address"];
_shippingAddress = json["shipping_address"];
if (json["addresses"] != null) {
_addresses = [];
json["addresses"].forEach((v) {
_addresses.add(Addresses.fromJson(v));
});
}
_customerGuid = json["customer_guid"];
_username = json["username"];
_email = json["email"];
@ -136,26 +172,22 @@ class PackagesCustomerResponseModel {
_lastActivityDateUtc = json["last_activity_date_utc"];
_registeredInStoreId = json["registered_in_store_id"];
_subscribedToNewsletter = json["subscribed_to_newsletter"];
_id = json["id"];
// if (json["role_ids"] != null) {
// _roleIds = [];
// json["role_ids"].forEach((v) {
// _roleIds.add(dynamic.fromJson(v));
// });
// }
// if (json["addresses"] != null) {
// _addresses = [];
// json["addresses"].forEach((v) {
// _addresses.add(dynamic.fromJson(v));
// });
// }
// if (json["shopping_cart_items"] != null) {
// _shoppingCartItems = [];
// json["shopping_cart_items"].forEach((v) {
// _shoppingCartItems.add(dynamic.fromJson(v));
// });
// }
if (json["role_ids"] != null) {
_roleIds = [];
json["role_ids"].forEach((v) {
_roleIds.add(v);
});
}
if (json["shopping_cart_items"] != null) {
_shoppingCartItems = [];
json["shopping_cart_items"].forEach((v) {
_shoppingCartItems.add(PackagesCartItemsResponseModel.fromJson(v));
});
}
_id = json["id"];
}
Map<String, dynamic> toJson() {
@ -190,10 +222,146 @@ class PackagesCustomerResponseModel {
map["registered_in_store_id"] = _registeredInStoreId;
map["subscribed_to_newsletter"] = _subscribedToNewsletter;
if (_roleIds != null) {
map["role_ids"] = _roleIds.map((v) => v.toJson()).toList();
map["role_ids"] = _roleIds.map((v) => v).toList();
}
map["id"] = _id;
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 '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/CreateCustomerRequestModel.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/PackagesResponseModel.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/client/base_app_client.dart';
import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart';
@ -24,7 +27,8 @@ class OffersAndPackagesServices extends BaseService {
List<PackagesResponseModel> latestOffersList = List();
List<PackagesResponseModel> bestSellerList = List();
List<PackagesResponseModel> bannersList = List();
List<CartProductResponseModel> cartItemList = List();
List<PackagesCartItemsResponseModel> cartItemList = List();
String cartItemCount = "";
PackagesCustomerResponseModel customer;
@ -154,15 +158,15 @@ class OffersAndPackagesServices extends BaseService {
// --------------------
// 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)
return Future.value(customer);
hasError = false;
var url = EXA_CART_API_BASE_URL + PACKAGES_CUSTOMER;
customer = null;
Future errorThrow;
_showLoading(context, showLoading);
var url = EXA_CART_API_BASE_URL + PACKAGES_CUSTOMER;
await baseAppClient.simplePost(url, body: request.json(), onSuccess: (dynamic stringResponse, int statusCode){
_hideLoading(context, showLoading);
@ -172,10 +176,13 @@ class OffersAndPackagesServices extends BaseService {
}, onFailure: (String error, int statusCode){
_hideLoading(context, showLoading);
errorThrow = Future.error(error);
log(error);
});
return customer;
await Future.delayed(Duration(seconds: 1));
return errorThrow ?? customer;
}
@ -183,7 +190,7 @@ class OffersAndPackagesServices extends BaseService {
// --------------------
// 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;
cartItemList.clear();
@ -194,7 +201,7 @@ class OffersAndPackagesServices extends BaseService {
var jsonResponse = json.decode(stringResponse);
jsonResponse['shopping_carts'].forEach((json) {
cartItemList.add(CartProductResponseModel.fromJson(json));
cartItemList.add(PackagesCartItemsResponseModel.fromJson(json));
});
}, onFailure: (String error, int statusCode) {
@ -206,8 +213,9 @@ class OffersAndPackagesServices extends BaseService {
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;
ResponseModel<PackagesCartItemsResponseModel> response;
request.customer_id = customer.id;
@ -217,14 +225,16 @@ class OffersAndPackagesServices extends BaseService {
_hideLoading(context, showLoading);
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){
_hideLoading(context, showLoading);
log(error);
errorThrow = Future.error(error);
errorThrow = Future.error(ResponseModel(status: true, data: null, error: error));
});
return errorThrow ?? true;
return errorThrow ?? response;
}
Future updateProductToCart(int cartItemID, {UpdateProductToCartRequestModel request, @required BuildContext context, bool showLoading = true}) async{
@ -268,21 +278,29 @@ class OffersAndPackagesServices extends BaseService {
// --------------------
// 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;
var jsonBody = {
"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);
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){
_hideLoading(context, showLoading);
var jsonResponse = json.decode(stringResponse);
order_id = jsonResponse['orders'][0]['id'];
}, onFailure: (String error, int statusCode){
_hideLoading(context, showLoading);
@ -290,7 +308,28 @@ class OffersAndPackagesServices extends BaseService {
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:diplomaticquarterapp/locator.dart';
class OfferCategoriesViewModel extends BaseViewModel {
class OfferCategoriesViewModel extends BaseViewModel{
OffersAndPackagesServices service = locator<OffersAndPackagesServices>();
get categoryList => service.categoryList;
get productList => service.categoryList;
}
class PackagesViewModel extends BaseViewModel {
@ -22,5 +23,15 @@ class PackagesViewModel extends BaseViewModel {
List<PackagesResponseModel> get latestOffersList => service.latestOffersList;
List<PackagesResponseModel> get bestSellerList => service.bestSellerList;
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>(
builder: (context, projectProvider, child) => MaterialApp(
showSemanticsDebugger: false,
title: 'Diplomatic Quarter App',
locale: projectProvider.appLocal,
@ -91,6 +90,7 @@ class MyApp extends StatelessWidget {
color: Color(0xffB8382C),
),
),
floatingActionButtonTheme: FloatingActionButtonThemeData(highlightElevation: 2, disabledElevation: 0, elevation: 2),
disabledColor: Colors.grey[300],
errorColor: Color.fromRGBO(235, 80, 60, 1.0),
scaffoldBackgroundColor: Color(0xffE9E9E9), // Colors.grey[100],
@ -115,8 +115,9 @@ class MyApp extends StatelessWidget {
),
),
),
// initialRoute: SPLASH,
initialRoute: PACKAGES_OFFERS,
initialRoute: SPLASH,
// initialRoute: PACKAGES_OFFERS,
// initialRoute: PACKAGES_ORDER_COMPLETED,
routes: routes,
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/base/base_view.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/pharmacies/screens/pharmacy_module_page.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))
Container(
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: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/OffersProductsRequestModel.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_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'CreateCustomerDailogPage.dart';
dynamic languageID;
class ClinicPackagesPage extends StatefulWidget {
@ -33,15 +37,39 @@ class ClinicPackagesPage extends StatefulWidget {
}
class _ClinicPackagesPageState extends State<ClinicPackagesPage> {
List<PackagesResponseModel> get _products => widget.products;
class _ClinicPackagesPageState extends State<ClinicPackagesPage> with AfterLayoutMixin<ClinicPackagesPage>{
AppScaffold appScaffold;
List<PackagesResponseModel> get _products => widget.products;
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
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
@ -50,7 +78,7 @@ class _ClinicPackagesPageState extends State<ClinicPackagesPage> {
onModelReady: (model){
viewModel = model;
},
builder: (_, model, wi) => AppScaffold(
builder: (_, model, wi) => appScaffold = AppScaffold(
appBarTitle: TranslationBase.of(context).offerAndPackages,
isShowAppBar: true,
isPharmacy: false,
@ -66,7 +94,7 @@ class _ClinicPackagesPageState extends State<ClinicPackagesPage> {
itemCount: _products.length,
itemBuilder: (BuildContext context, int index) => new Container(
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),
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: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/OffersCategoriesRequestModel.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/packages_offers/ClinicOfferAndPackagesPage.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/uitl/gif_loader_dialog_utils.dart';
import 'package:diplomaticquarterapp/uitl/utils.dart' as utils;
import 'package:diplomaticquarterapp/widgets/Loader/gif_loader_container.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/offers_packages/PackagesCartItemCard.dart';
import 'package:diplomaticquarterapp/widgets/offers_packages/PackagesOfferCard.dart';
@ -73,7 +77,21 @@ class _PackagesCartPageState extends State<PackagesCartPage> with AfterLayoutMix
}
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
@ -124,10 +142,10 @@ class _PackagesCartPageState extends State<PackagesCartPage> with AfterLayoutMix
itemModel: item,
shouldStepperChangeApply: (apply,total) async{
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);
});
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) {});
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 */
// ---------------------------
String _selectedPaymentMethod;
Widget _paymentOptions(BuildContext context, Function(String) onSelected) {
double height = 22;
double height = 30;
Widget buttonContent(bool isSelected, String imageName) {
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/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/CreateCustomerDailogPage.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';
@ -85,120 +87,123 @@ class _PackagesHomePageState extends State<PackagesHomePage> with AfterLayoutMix
onProductCartClick(PackagesResponseModel product) async {
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);
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);
});
}
}
AppScaffold appScaffold;
@override
Widget build(BuildContext context) {
return BaseView<PackagesViewModel>(
allowAny: true,
onModelReady: (model) => viewModel = model,
builder: (_, model, wi){
return
AppScaffold(
appBarTitle: TranslationBase.of(context).offerAndPackages,
isShowAppBar: true,
isPharmacy: false,
showPharmacyCart: false,
showHomeAppBarIcon: false,
isOfferPackages: true,
showOfferPackagesCart: true,
isShowDecPage: false,
body: ListView(
children: [
// Top Banner Carousel
AspectRatio(
aspectRatio: 2.2/1,
child: bannerCarousel()
),
Center(
child: CarouselIndicator(
activeColor: Theme.of(context).appBarTheme.color,
color: Colors.grey[300],
cornerRadius: 15,
width: 15, height: 15,
count: _bannerCarousel.itemCount,
index: carouselIndicatorIndex,
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(
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);
}),
appScaffold =
AppScaffold(
appBarTitle: TranslationBase.of(context).offerAndPackages,
isShowAppBar: true,
isPharmacy: false,
showPharmacyCart: false,
showHomeAppBarIcon: false,
isOfferPackages: true,
showOfferPackagesCart: true,
isShowDecPage: false,
body: ListView(
children: [
// Top Banner Carousel
AspectRatio(
aspectRatio: 2.2/1,
child: bannerCarousel()
),
Center(
child: CarouselIndicator(
activeColor: Theme.of(context).appBarTheme.color,
color: Colors.grey[300],
cornerRadius: 15,
width: 15, height: 15,
count: _bannerCarousel.itemCount,
index: carouselIndicatorIndex,
onClick: (index){
debugPrint('onClick at ${index}');
},
),
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);
}),
)
],),
),
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(
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/packages_offers/OfferAndPackagesCartPage.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/symptom-checker/info.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 PACKAGES_OFFERS = 'packages-offers';
const String PACKAGES_OFFERS_CART = 'packages-offers-cart';
const String PACKAGES_ORDER_COMPLETED = 'packages-offers-cart';
var routes = {
SPLASH: (_) => SplashScreen(),
@ -60,4 +62,5 @@ var routes = {
SETTINGS: (_) => Settings(),
PACKAGES_OFFERS: (_) => PackagesHomePage(),
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 'package:diplomaticquarterapp/config/config.dart';
import 'package:diplomaticquarterapp/config/shared_pref_kay.dart';
import 'package:diplomaticquarterapp/models/Appointments/AppoimentAllHistoryResultList.dart';
import 'package:diplomaticquarterapp/models/Authentication/authenticated_user.dart';
import 'package:diplomaticquarterapp/services/authentication/auth_provider.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';
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 {
_PAYMENT_TYPE paymentType;
static String SERVICE_URL =
'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 =
// '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 = [
'success',
'PayFortResponse',
@ -30,6 +48,7 @@ class MyInAppBrowser extends InAppBrowser {
final Function onExitCallback;
final Function onLoadStartCallback;
final BuildContext context;
AppSharedPreferences sharedPref = AppSharedPreferences();
AuthProvider authProvider = new AuthProvider();
@ -45,7 +64,7 @@ class MyInAppBrowser extends InAppBrowser {
static bool isPaymentDone = false;
MyInAppBrowser({this.onExitCallback, this.appo, this.onLoadStartCallback});
MyInAppBrowser({this.onExitCallback, this.appo, this.onLoadStartCallback, this.context});
Future onBrowserCreated() async {
print("\n\nBrowser Created!\n\n");
@ -53,7 +72,8 @@ class MyInAppBrowser extends InAppBrowser {
@override
Future onLoadStart(String url) async {
onLoadStartCallback(url);
if(onLoadStartCallback != null)
onLoadStartCallback(url);
}
@override
@ -74,13 +94,20 @@ class MyInAppBrowser extends InAppBrowser {
@override
void onExit() {
print("\n\nBrowser closed!\n\n");
onExitCallback(appo, isPaymentDone);
if(onExitCallback != null)
onExitCallback(appo, isPaymentDone);
}
@override
Future<ShouldOverrideUrlLoadingAction> shouldOverrideUrlLoading(
ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest) async {
print("\n\n override ${shouldOverrideUrlLoadingRequest.url}\n\n");
Future<ShouldOverrideUrlLoadingAction> shouldOverrideUrlLoading(ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest) async {
var url = shouldOverrideUrlLoadingRequest.url;
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;
}
@ -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(
double amount,
String orderDesc,
@ -142,13 +175,15 @@ class MyInAppBrowser extends InAppBrowser {
clinicID,
doctorID)
.then((value) {
this.browser.openUrl(url: value);
paymentType = _PAYMENT_TYPE.PATIENT;
this.browser.openUrl(url: value, options: _InAppBrowserOptions);
});
}
openBrowser(String url) {
this.browser = browser;
this.browser.openUrl(url: url);
this.browser.openUrl(url: url, options: _InAppBrowserOptions);
}
Future<String> generateURL(
@ -311,4 +346,4 @@ class MyChromeSafariBrowser extends ChromeSafariBrowser {
void onClosed() {
print("ChromeSafari browser closed");
}
}
}

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

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

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

Loading…
Cancel
Save