From 516df96e212546e15657ceef3ca266b114d5bae0 Mon Sep 17 00:00:00 2001 From: Zohaib Iqbal Kambrani <> Date: Tue, 23 Feb 2021 16:07:23 +0300 Subject: [PATCH 01/26] no message --- lib/config/config.dart | 4 + lib/core/model/pharmacies/order_model.dart | 15 +- .../parmacyModule/order-preview-service.dart | 24 ++++ .../order_model_view_model.dart | 3 +- lib/pages/pharmacy/order/OrderDetails.dart | 18 ++- lib/pages/pharmacy/order/TrackDriver.dart | 130 +++++++++++++++--- pubspec.yaml | 4 + 7 files changed, 169 insertions(+), 29 deletions(-) diff --git a/lib/config/config.dart b/lib/config/config.dart index be5dd440..cf1836ac 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -26,6 +26,10 @@ const GET_PROJECT = 'Services/Lists.svc/REST/GetProject'; ///Geofencing const GET_GEO_ZONES = 'Services/Patients.svc/REST/GeoF_GetAllPoints'; const LOG_GEO_ZONES = 'Services/Patients.svc/REST/GeoF_InsertPatientFileInfo'; + +// Delivery Driver +const DRIVER_LOCATION = 'Services/Patients.svc/REST/PatientER_GetDriverLocation'; + //weather const WEATHER_INDICATOR = 'Services/Weather.svc/REST/GetCityInfo'; diff --git a/lib/core/model/pharmacies/order_model.dart b/lib/core/model/pharmacies/order_model.dart index 8872aaf8..776c21ec 100644 --- a/lib/core/model/pharmacies/order_model.dart +++ b/lib/core/model/pharmacies/order_model.dart @@ -73,6 +73,8 @@ class OrderModel { this.preferDeliveryDate, this.preferDeliveryTime, this.preferDeliveryTimen, + this.driverID, + this.driverOTP, }); String id; @@ -138,6 +140,8 @@ class OrderModel { DateTime preferDeliveryDate; PreferDeliveryTime preferDeliveryTime; PreferDeliveryTimen preferDeliveryTimen; + String driverOTP; + String driverID; factory OrderModel.fromJson(Map json) => OrderModel( id: json["id"], @@ -203,6 +207,11 @@ class OrderModel { preferDeliveryDate: json["prefer_delivery_date"] == null ? null : DateTime.parse(json["prefer_delivery_date"]), preferDeliveryTime: json["prefer_delivery_time"] == null ? null : preferDeliveryTimeValues.map[json["prefer_delivery_time"]], preferDeliveryTimen: json["prefer_delivery_timen"] == null ? null : preferDeliveryTimenValues.map[json["prefer_delivery_timen"]], + + // Driver Detail + driverID: json["DriverID"], + driverOTP: json["DriverOTP"], + ); Map toJson() => { @@ -1364,7 +1373,7 @@ final titleValues = EnumValues({ "ممتاز": Title.TITLE }); -enum OrderStatus { ORDER_SUBMITTED, PENDING, ORDER_IN_PROGRESS, ORDER_COMPLETED, CANCELLED, PROCESSING, ORDER_REFUNDED, COMPLETE } +enum OrderStatus { ORDER_SUBMITTED, PENDING, ORDER_IN_PROGRESS,ORDER_SENT_FOR_DELIVERY, ORDER_COMPLETED, CANCELLED, PROCESSING, ORDER_REFUNDED, COMPLETE } final orderStatusValues = EnumValues({ "Cancelled": OrderStatus.CANCELLED, @@ -1374,7 +1383,8 @@ final orderStatusValues = EnumValues({ "OrderRefunded": OrderStatus.ORDER_REFUNDED, "OrderSubmitted": OrderStatus.ORDER_SUBMITTED, "Pending": OrderStatus.PENDING, - "Processing": OrderStatus.PROCESSING + "Processing": OrderStatus.PROCESSING, + "orderSentForDelivery": OrderStatus.ORDER_SENT_FOR_DELIVERY }); enum OrderStatusn { ORDER_SUBMITTED, EMPTY, ORDER_IN_PROGRESS, ORDER_COMPLETED, ORDER_STATUSN, PURPLE, FLUFFY, TENTACLED } @@ -1387,6 +1397,7 @@ final orderStatusnValues = EnumValues({ "ملغي": OrderStatusn.ORDER_STATUSN, "Order Submitted": OrderStatusn.ORDER_SUBMITTED, "قيد التنفيذ": OrderStatusn.PURPLE, + "مكتمل": OrderStatusn.TENTACLED, "مكتمل": OrderStatusn.TENTACLED }); diff --git a/lib/core/service/parmacyModule/order-preview-service.dart b/lib/core/service/parmacyModule/order-preview-service.dart index 18cfa87e..8bfda569 100644 --- a/lib/core/service/parmacyModule/order-preview-service.dart +++ b/lib/core/service/parmacyModule/order-preview-service.dart @@ -6,6 +6,8 @@ import 'package:diplomaticquarterapp/core/model/pharmacies/ShoppingCart.dart'; import 'package:diplomaticquarterapp/core/model/pharmacies/payment-checkout-data.dart'; import 'package:diplomaticquarterapp/core/service/base_service.dart'; import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/OrderPreviewViewModel.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:google_maps_flutter/google_maps_flutter.dart'; class OrderPreviewService extends BaseService { bool isFinished = true; @@ -245,4 +247,26 @@ class OrderPreviewService extends BaseService { return ""; } } + + Future getDriverLocation(dynamic driverId) async{ + Map jsonBody = Map(); + jsonBody['DriverID'] = driverId; + + LatLng coordinates; + await baseAppClient.post(DRIVER_LOCATION, + onSuccess: (response, statusCode) async { + if(statusCode == 200){ + dynamic locationObject = response['PatientER_GetDriverLocationList'][0]; + double lat = locationObject['Latitude']; + double lon = locationObject['Longitude']; + if(lat != null && lon != null){ + coordinates = LatLng(lat,lon); + } + } + }, onFailure: (String error, int statusCode) { + + }, body: jsonBody); + + return coordinates; + } } diff --git a/lib/core/viewModels/pharmacyModule/order_model_view_model.dart b/lib/core/viewModels/pharmacyModule/order_model_view_model.dart index f434db54..90881d7e 100644 --- a/lib/core/viewModels/pharmacyModule/order_model_view_model.dart +++ b/lib/core/viewModels/pharmacyModule/order_model_view_model.dart @@ -50,7 +50,7 @@ class OrderModelViewModel extends BaseViewModel { } } - Future getOrderDetails(OrderId) async { + Future getOrderDetails(OrderId) async { setState(ViewState.Busy); await _orderDetailsService.getOrderDetails(OrderId); if (_orderDetailsService.hasError) { @@ -59,6 +59,7 @@ class OrderModelViewModel extends BaseViewModel { } else { setState(ViewState.Idle); } + return _orderDetailsService.orderList.first; } Future getProductReview() async { diff --git a/lib/pages/pharmacy/order/OrderDetails.dart b/lib/pages/pharmacy/order/OrderDetails.dart index 670cb951..f3ee5447 100644 --- a/lib/pages/pharmacy/order/OrderDetails.dart +++ b/lib/pages/pharmacy/order/OrderDetails.dart @@ -48,7 +48,7 @@ class _OrderDetailsPageState extends State { var model; var isCancel = false; var isRefund = false; - var isActiveDelivery = true; + var isActiveDelivery = false; var dataIsCancel; var dataIsRefund; @@ -66,7 +66,13 @@ class _OrderDetailsPageState extends State { @override Widget build(BuildContext context) { return BaseView( - onModelReady: (model) => model.getOrderDetails(widget.orderModel.id), + onModelReady: (model){ + model.getOrderDetails(widget.orderModel.id).then((value){ + setState(() { + isActiveDelivery = (value.orderStatusId == 995 && (value.driverID != null && value.driverID.isNotEmpty)); + }); + }); + }, builder: (_, model, wi) => AppScaffold( appBarTitle: TranslationBase.of(context).orderDetail, isShowAppBar: true, @@ -596,10 +602,10 @@ class _OrderDetailsPageState extends State { isActiveDelivery ? InkWell( onTap: () { - // Navigator.push( - // context, - // MaterialPageRoute(builder: (context) => TrackDriver(order: widget.orderModel), - // )); + Navigator.push( + context, + MaterialPageRoute(builder: (context) => TrackDriver(order: model.orderListModel.first), + )); }, child: Container( height: 50.0, diff --git a/lib/pages/pharmacy/order/TrackDriver.dart b/lib/pages/pharmacy/order/TrackDriver.dart index b9a8056f..5a2e20c8 100644 --- a/lib/pages/pharmacy/order/TrackDriver.dart +++ b/lib/pages/pharmacy/order/TrackDriver.dart @@ -1,12 +1,19 @@ import 'dart:async'; +import 'package:async/async.dart'; import 'package:diplomaticquarterapp/config/config.dart'; import 'package:diplomaticquarterapp/core/model/pharmacies/order_model.dart'; +import 'package:diplomaticquarterapp/core/service/parmacyModule/order-preview-service.dart'; +import 'package:diplomaticquarterapp/locator.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_animarker/lat_lng_interpolation.dart'; +import 'package:flutter_animarker/models/lat_lng_delta.dart'; +import 'package:flutter_animarker/models/lat_lng_info.dart'; import 'package:flutter_polyline_points/flutter_polyline_points.dart'; +import 'package:geolocator/geolocator.dart'; import 'package:google_maps_flutter/google_maps_flutter.dart'; import 'package:location/location.dart'; - +import 'package:flutter_animarker/streams/lat_lng_stream.dart'; class TrackDriver extends StatefulWidget { final OrderModel order; @@ -17,12 +24,13 @@ class TrackDriver extends StatefulWidget { } class _TrackDriverState extends State { + OrderPreviewService _orderServices = locator(); OrderModel _order; Completer _controller = Completer(); - double CAMERA_ZOOM = 16; + double CAMERA_ZOOM = 14; double CAMERA_TILT = 0; double CAMERA_BEARING = 30; LatLng SOURCE_LOCATION = null; @@ -39,17 +47,63 @@ class _TrackDriverState extends State { BitmapDescriptor destinationIcon; // for my custom marker pins Location location;// wrapper around the location API + + int locationUpdateFreq = 2; + LatLngInterpolationStream _latLngStream; + StreamGroup subscriptions; + @override void initState() { + _order = widget.order; DEST_LOCATION = _order.shippingAddress.getLocation(); location = new Location(); polylinePoints = PolylinePoints(); setSourceAndDestinationIcons(); + + initMarkerUpdateStream(); + startUpdatingDriverLocation(); + + super.initState(); + } + + @override + void dispose() { + super.dispose(); + subscriptions.close(); + _latLngStream.cancel(); + stopUpdatingDriverLocation(); + } + + initMarkerUpdateStream(){ + _latLngStream = LatLngInterpolationStream(movementDuration: Duration(seconds: locationUpdateFreq+1)); + subscriptions = StreamGroup(); + + subscriptions.add(_latLngStream.getAnimatedPosition('sourcePin')); + subscriptions.stream.listen((LatLngDelta delta) { + //Update the marker with animation + setState(() { + //Get the marker Id for this animation + var markerId = MarkerId(delta.markerId); + Marker sourceMarker = Marker( + markerId: markerId, + // rotation: delta.rotation, + icon: sourceIcon, + position: LatLng( + delta.from.latitude, + delta.from.longitude, + ), + ); + + _markers.removeWhere((m) => m.markerId.value == 'sourcePin'); + _markers.add(sourceMarker); + }); + }); } @override Widget build(BuildContext context) { + return new Scaffold( body: GoogleMap( myLocationEnabled: true, @@ -63,11 +117,11 @@ class _TrackDriverState extends State { showPinsOnMap(); }, ), - floatingActionButton: FloatingActionButton.extended( - onPressed: _goToDriver, - label: Text('To the lake!'), - icon: Icon(Icons.directions_boat), - ), + // floatingActionButton: FloatingActionButton.extended( + // onPressed: _goToDriver, + // label: Text('To the lake!'), + // icon: Icon(Icons.directions_boat), + // ), ); } @@ -130,6 +184,7 @@ class _TrackDriverState extends State { if(SOURCE_LOCATION != null){ setState(() { var pinPosition = SOURCE_LOCATION; + _markers.removeWhere((m) => m.markerId.value == 'sourcePin'); _markers.add(Marker( markerId: MarkerId('sourcePin'), position: pinPosition, @@ -142,6 +197,7 @@ class _TrackDriverState extends State { if(DEST_LOCATION != null){ setState(() { var destPosition = DEST_LOCATION; + _markers.removeWhere((m) => m.markerId.value == 'destPin'); _markers.add(Marker( markerId: MarkerId('destPin'), position: destPosition, @@ -166,21 +222,26 @@ class _TrackDriverState extends State { ); final GoogleMapController controller = await _controller.future; controller.animateCamera(CameraUpdate.newCameraPosition(cPosition)); + + _latLngStream.addLatLng(LatLngInfo(SOURCE_LOCATION.latitude, SOURCE_LOCATION.longitude, "sourcePin")); + // do this inside the setState() so Flutter gets notified // that a widget update is due - setState(() { - // updated position - var pinPosition = SOURCE_LOCATION; - - // the trick is to remove the marker (by id) - // and add it again at the updated location - _markers.removeWhere((m) => m.markerId.value == 'sourcePin'); - _markers.add(Marker( - markerId: MarkerId('sourcePin'), - position: pinPosition, // updated position - icon: sourceIcon - )); - }); + // setState(() { + // // updated position + // var pinPosition = SOURCE_LOCATION; + // + // // the trick is to remove the marker (by id) + // // and add it again at the updated location + // _markers.removeWhere((m) => m.markerId.value == 'sourcePin'); + // _markers.add(Marker( + // markerId: MarkerId('sourcePin'), + // position: pinPosition, // updated position + // icon: sourceIcon + // )); + // }); + + drawRoute(); } void drawRoute() async { @@ -208,4 +269,33 @@ class _TrackDriverState extends State { }); } } + + bool isLocationUpdating = false; + startUpdatingDriverLocation({int frequencyInSeconds = 2}) async{ + isLocationUpdating = true; + int driverId = int.tryParse(_order.driverID); + + Future.doWhile(() async{ + await Future.delayed(Duration(seconds: frequencyInSeconds)); + if(isLocationUpdating){ + LatLng driverLocation = (await _orderServices.getDriverLocation(driverId)); + if(driverLocation != null){ + if(SOURCE_LOCATION == null || DEST_LOCATION == null){ + SOURCE_LOCATION = driverLocation; + DEST_LOCATION = _order.shippingAddress.getLocation(); + showPinsOnMap(); + } + SOURCE_LOCATION = driverLocation; + updatePinOnMap(); + } + } + return isLocationUpdating; + + }); + + } + + stopUpdatingDriverLocation(){ + isLocationUpdating = false; + } } \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 2c07d0c9..3b44f01f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -21,6 +21,7 @@ dependencies: # http client http: ^0.12.1 connectivity: ^0.4.9+3 + async: ^2.4.2 # State Management provider: ^4.3.2+2 @@ -170,6 +171,9 @@ dependencies: # Dep by Zohaib shimmer: ^1.1.2 + # Marker Animation + flutter_animarker: ^1.0.0 + dev_dependencies: flutter_test: sdk: flutter From 63663f1b24969e6eb3a8f24abdea75e427b2f5b1 Mon Sep 17 00:00:00 2001 From: Zohaib Iqbal Kambrani <> Date: Wed, 24 Feb 2021 16:35:10 +0300 Subject: [PATCH 02/26] Track Delivery Driver Completed --- ios/Runner.xcodeproj/project.pbxproj | 18 +++++++++++ ios/Runner/AppDelegate.swift | 2 +- lib/config/localized_values.dart | 1 + lib/pages/pharmacy/order/TrackDriver.dart | 34 ++++++++++++++++----- lib/uitl/translations_delegate_base.dart | 1 + lib/widgets/others/app_scaffold_widget.dart | 7 ++++- 6 files changed, 53 insertions(+), 10 deletions(-) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 366647c0..a48231b2 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -220,6 +220,7 @@ 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, EFDAD5E1235DCA1DB6187148 /* [CP] Embed Pods Frameworks */, + A22727229BC544AD6D5B2B5F /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -333,6 +334,23 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + A22727229BC544AD6D5B2B5F /* [CP] Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Copy Pods Resources"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; EFDAD5E1235DCA1DB6187148 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 2dc828d1..c4a74c80 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -11,7 +11,7 @@ var userNotificationCenterDelegate:UNUserNotificationCenterDelegate? = nil override func application( _ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - GMSServices.provideAPIKey("AIzaSyCiiJiHkocPbcziHt9O8rGWavDrxHRQys8") + GMSServices.provideAPIKey("AIzaSyCmevVlr2Bh-c8W1VUzo8gt8JRY7n5PANw") GeneratedPluginRegistrant.register(with: self) initializePlatformChannel() diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index a6b4d219..614f3a54 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -378,6 +378,7 @@ const Map localizedValues = { "History": {"en": "History", "ar": "السجلات"}, "OrderNo": {"en": "Order No", "ar": "رقم الطلب"}, "OrderDetails": {"en": "Order Details", "ar": "تفاصيل الطلب"}, + "DeliveryDriverTrack": {"en": "Driver Tracking", "ar": "تتبع السائق"}, "VitalSign": {"en": "Vital Sign", "ar": "العلامة حيوية"}, "MonthlyReports": {"en": "Monthly Reports", "ar": "تقارير شهرية"}, "km": {"en": "KMs:", "ar": "كم"}, diff --git a/lib/pages/pharmacy/order/TrackDriver.dart b/lib/pages/pharmacy/order/TrackDriver.dart index 5a2e20c8..89e75e19 100644 --- a/lib/pages/pharmacy/order/TrackDriver.dart +++ b/lib/pages/pharmacy/order/TrackDriver.dart @@ -1,11 +1,16 @@ import 'dart:async'; +import 'dart:typed_data'; +import 'dart:ui' as ui; import 'package:async/async.dart'; import 'package:diplomaticquarterapp/config/config.dart'; import 'package:diplomaticquarterapp/core/model/pharmacies/order_model.dart'; import 'package:diplomaticquarterapp/core/service/parmacyModule/order-preview-service.dart'; import 'package:diplomaticquarterapp/locator.dart'; +import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_animarker/lat_lng_interpolation.dart'; import 'package:flutter_animarker/models/lat_lng_delta.dart'; import 'package:flutter_animarker/models/lat_lng_info.dart'; @@ -104,7 +109,12 @@ class _TrackDriverState extends State { @override Widget build(BuildContext context) { - return new Scaffold( + return AppScaffold( + appBarTitle: TranslationBase.of(context).deliveryDriverTrack, + isShowAppBar: true, + isPharmacy: true, + showPharmacyCart: false, + showHomeAppBarIcon: false, body: GoogleMap( myLocationEnabled: true, compassEnabled: true, @@ -127,13 +137,10 @@ class _TrackDriverState extends State { void setSourceAndDestinationIcons() async { - sourceIcon = await BitmapDescriptor.fromAssetImage( - ImageConfiguration(devicePixelRatio: 2.5), - 'assets/images/map_markers/source_map_marker.png'); - - destinationIcon = await BitmapDescriptor.fromAssetImage( - ImageConfiguration(devicePixelRatio: 2.5), - 'assets/images/map_markers/destination_map_marker.png'); + final Uint8List srcMarkerBytes = await getBytesFromAsset('assets/images/map_markers/source_map_marker.png', getMarkerIconSize()); + final Uint8List destMarkerBytes = await getBytesFromAsset('assets/images/map_markers/destination_map_marker.png', getMarkerIconSize()); + sourceIcon = await BitmapDescriptor.fromBytes(srcMarkerBytes); + destinationIcon = await BitmapDescriptor.fromBytes(destMarkerBytes); } CameraPosition _orderDeliveryLocationCamera(){ @@ -298,4 +305,15 @@ class _TrackDriverState extends State { stopUpdatingDriverLocation(){ isLocationUpdating = false; } + + Future getBytesFromAsset(String path, int width) async { + ByteData data = await rootBundle.load(path); + ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(), targetWidth: width); + ui.FrameInfo fi = await codec.getNextFrame(); + return (await fi.image.toByteData(format: ui.ImageByteFormat.png)).buffer.asUint8List(); + } + + int getMarkerIconSize(){ + return 140; + } } \ No newline at end of file diff --git a/lib/uitl/translations_delegate_base.dart b/lib/uitl/translations_delegate_base.dart index a3d67127..557dc6f7 100644 --- a/lib/uitl/translations_delegate_base.dart +++ b/lib/uitl/translations_delegate_base.dart @@ -562,6 +562,7 @@ class TranslationBase { String get reviewComment => localizedValues['reviewComment'][locale.languageCode]; String get shippedMethod => localizedValues['shippedMethod'][locale.languageCode]; String get orderDetail => localizedValues['orderDetail'][locale.languageCode]; + String get deliveryDriverTrack => localizedValues['DeliveryDriverTrack'][locale.languageCode]; String get subtotal => localizedValues['subtotal'][locale.languageCode]; String get shipping => localizedValues['shipping'][locale.languageCode]; String get shipBy => localizedValues['shipBy'][locale.languageCode]; diff --git a/lib/widgets/others/app_scaffold_widget.dart b/lib/widgets/others/app_scaffold_widget.dart index e5381ccb..ca91efe2 100644 --- a/lib/widgets/others/app_scaffold_widget.dart +++ b/lib/widgets/others/app_scaffold_widget.dart @@ -38,6 +38,7 @@ class AppScaffold extends StatelessWidget { final bool isBottomBar; final Widget floatingActionButton; final bool isPharmacy; + final bool showPharmacyCart; final String title; final String description; final bool isShowDecPage; @@ -61,6 +62,7 @@ class AppScaffold extends StatelessWidget { this.baseViewModel, this.floatingActionButton, this.isPharmacy = false, + this.showPharmacyCart = true, this.title, this.description, this.isShowDecPage = true, @@ -84,6 +86,7 @@ class AppScaffold extends StatelessWidget { appBarIcons: appBarIcons, showHomeAppBarIcon: showHomeAppBarIcon, isPharmacy: isPharmacy, + showPharmacyCart: showPharmacyCart, isShowDecPage: isShowDecPage, ) : null, @@ -119,6 +122,7 @@ class AppBarWidget extends StatelessWidget with PreferredSizeWidget { final bool showHomeAppBarIcon; final List appBarIcons; final bool isPharmacy; + final bool showPharmacyCart; final bool isShowDecPage; AppBarWidget( @@ -126,6 +130,7 @@ class AppBarWidget extends StatelessWidget with PreferredSizeWidget { this.showHomeAppBarIcon, this.appBarIcons, this.isPharmacy = true, + this.showPharmacyCart = true, this.isShowDecPage = true}); @override @@ -157,7 +162,7 @@ class AppBarWidget extends StatelessWidget with PreferredSizeWidget { ), centerTitle: true, actions: [ - isPharmacy + (isPharmacy && showPharmacyCart) ? IconButton( icon: Icon(Icons.shopping_cart), color: Colors.white, From 15ec3ec9b98dc68dbe204c96d26298ddf5c4170f Mon Sep 17 00:00:00 2001 From: Zohaib Iqbal Kambrani <> Date: Wed, 24 Feb 2021 18:18:26 +0300 Subject: [PATCH 03/26] Translation Track Driver, enhancement, initial camera --- lib/config/localized_values.dart | 2 + lib/pages/pharmacy/order/TrackDriver.dart | 142 +++++++++++++--------- lib/uitl/translations_delegate_base.dart | 2 + 3 files changed, 87 insertions(+), 59 deletions(-) diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index 614f3a54..6ab1a723 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -379,6 +379,8 @@ const Map localizedValues = { "OrderNo": {"en": "Order No", "ar": "رقم الطلب"}, "OrderDetails": {"en": "Order Details", "ar": "تفاصيل الطلب"}, "DeliveryDriverTrack": {"en": "Driver Tracking", "ar": "تتبع السائق"}, + "DeliveryLocation": {"en": "Delivery Location", "ar": "موقع التسليم"}, + "Driver": {"en": "Driver", "ar": "السائق"}, "VitalSign": {"en": "Vital Sign", "ar": "العلامة حيوية"}, "MonthlyReports": {"en": "Monthly Reports", "ar": "تقارير شهرية"}, "km": {"en": "KMs:", "ar": "كم"}, diff --git a/lib/pages/pharmacy/order/TrackDriver.dart b/lib/pages/pharmacy/order/TrackDriver.dart index 89e75e19..3b8779dd 100644 --- a/lib/pages/pharmacy/order/TrackDriver.dart +++ b/lib/pages/pharmacy/order/TrackDriver.dart @@ -7,6 +7,7 @@ import 'package:diplomaticquarterapp/config/config.dart'; import 'package:diplomaticquarterapp/core/model/pharmacies/order_model.dart'; import 'package:diplomaticquarterapp/core/service/parmacyModule/order-preview-service.dart'; import 'package:diplomaticquarterapp/locator.dart'; +import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; import 'package:flutter/material.dart'; @@ -59,6 +60,7 @@ class _TrackDriverState extends State { @override void initState() { + super.initState(); _order = widget.order; DEST_LOCATION = _order.shippingAddress.getLocation(); @@ -69,7 +71,6 @@ class _TrackDriverState extends State { initMarkerUpdateStream(); startUpdatingDriverLocation(); - super.initState(); } @override @@ -98,6 +99,7 @@ class _TrackDriverState extends State { delta.from.latitude, delta.from.longitude, ), + onTap: onSourceMarkerTap ); _markers.removeWhere((m) => m.markerId.value == 'sourcePin'); @@ -121,10 +123,10 @@ class _TrackDriverState extends State { markers: _markers, polylines: _polylines, mapType: MapType.normal, - initialCameraPosition: _orderDeliveryLocationCamera(), + initialCameraPosition: CameraPosition(target: DEST_LOCATION, zoom: 4), onMapCreated: (GoogleMapController controller) { _controller.complete(controller); - showPinsOnMap(); + // showPinsOnMap(); }, ), // floatingActionButton: FloatingActionButton.extended( @@ -144,22 +146,27 @@ class _TrackDriverState extends State { } CameraPosition _orderDeliveryLocationCamera(){ - - final CameraPosition orderDeliveryLocCamera = CameraPosition( - bearing: CAMERA_BEARING, - target: DEST_LOCATION, - tilt: CAMERA_TILT, - zoom: CAMERA_ZOOM); - return orderDeliveryLocCamera; + if(DEST_LOCATION != null){ + final CameraPosition orderDeliveryLocCamera = CameraPosition( + bearing: CAMERA_BEARING, + target: DEST_LOCATION, + tilt: CAMERA_TILT, + zoom: CAMERA_ZOOM); + return orderDeliveryLocCamera; + } + return null; } CameraPosition _driverLocationCamera(){ - final CameraPosition driverLocCamera = CameraPosition( - bearing: CAMERA_BEARING, - target: SOURCE_LOCATION, - tilt: CAMERA_TILT, - zoom: CAMERA_ZOOM); - return driverLocCamera; + if(DEST_LOCATION != null) { + final CameraPosition driverLocCamera = CameraPosition( + bearing: CAMERA_BEARING, + target: SOURCE_LOCATION, + tilt: CAMERA_TILT, + zoom: CAMERA_ZOOM); + return driverLocCamera; + } + return null; } @@ -176,16 +183,6 @@ class _TrackDriverState extends State { } - Future _fitCameraBetweenBothPoints() async { - final GoogleMapController controller = await _controller.future; - final CameraPosition driverLocCamera = CameraPosition( - bearing: CAMERA_BEARING, - target: SOURCE_LOCATION, - tilt: CAMERA_TILT, - zoom: CAMERA_ZOOM); - controller.animateCamera(CameraUpdate.newCameraPosition(driverLocCamera)); - } - void showPinsOnMap() { // source pin if(SOURCE_LOCATION != null){ @@ -195,7 +192,9 @@ class _TrackDriverState extends State { _markers.add(Marker( markerId: MarkerId('sourcePin'), position: pinPosition, - icon: sourceIcon + icon: sourceIcon, + infoWindow: InfoWindow(title: TranslationBase.of(context).driver), + onTap: onSourceMarkerTap )); }); } @@ -208,7 +207,9 @@ class _TrackDriverState extends State { _markers.add(Marker( markerId: MarkerId('destPin'), position: destPosition, - icon: destinationIcon + icon: destinationIcon, + infoWindow: InfoWindow(title: TranslationBase.of(context).deliveryLocation), + onTap: onDestinationMarkerTap )); }); } @@ -218,36 +219,7 @@ class _TrackDriverState extends State { } void updatePinOnMap() async { - // create a new CameraPosition instance - // every time the location changes, so the camera - // follows the pin as it moves with an animation - CameraPosition cPosition = CameraPosition( - zoom: CAMERA_ZOOM, - tilt: CAMERA_TILT, - bearing: CAMERA_BEARING, - target: SOURCE_LOCATION, - ); - final GoogleMapController controller = await _controller.future; - controller.animateCamera(CameraUpdate.newCameraPosition(cPosition)); - _latLngStream.addLatLng(LatLngInfo(SOURCE_LOCATION.latitude, SOURCE_LOCATION.longitude, "sourcePin")); - - // do this inside the setState() so Flutter gets notified - // that a widget update is due - // setState(() { - // // updated position - // var pinPosition = SOURCE_LOCATION; - // - // // the trick is to remove the marker (by id) - // // and add it again at the updated location - // _markers.removeWhere((m) => m.markerId.value == 'sourcePin'); - // _markers.add(Marker( - // markerId: MarkerId('sourcePin'), - // position: pinPosition, // updated position - // icon: sourceIcon - // )); - // }); - drawRoute(); } @@ -283,9 +255,14 @@ class _TrackDriverState extends State { int driverId = int.tryParse(_order.driverID); Future.doWhile(() async{ - await Future.delayed(Duration(seconds: frequencyInSeconds)); if(isLocationUpdating){ + + await Future.delayed(Duration(seconds: frequencyInSeconds)); + + showLoading(); LatLng driverLocation = (await _orderServices.getDriverLocation(driverId)); + hideLoading(); + if(driverLocation != null){ if(SOURCE_LOCATION == null || DEST_LOCATION == null){ SOURCE_LOCATION = driverLocation; @@ -294,12 +271,26 @@ class _TrackDriverState extends State { } SOURCE_LOCATION = driverLocation; updatePinOnMap(); + updateMapCamera(); + }else{ + GifLoaderDialogUtils.hideDialog(context); } } return isLocationUpdating; }); + } + showLoading(){ + if(SOURCE_LOCATION == null){ + GifLoaderDialogUtils.showMyDialog(context); + } + } + + hideLoading(){ + if(SOURCE_LOCATION == null){ + GifLoaderDialogUtils.hideDialog(context); + } } stopUpdatingDriverLocation(){ @@ -316,4 +307,37 @@ class _TrackDriverState extends State { int getMarkerIconSize(){ return 140; } -} \ No newline at end of file + + updateMapCamera() async{ + if(SOURCE_LOCATION != null && DEST_LOCATION != null){ + + // 'package:google_maps_flutter_platform_interface/src/types/location.dart': Failed assertion: line 72 pos 16: 'southwest.latitude <= northeast.latitude': is not true. + LatLngBounds bound; + if(SOURCE_LOCATION.latitude <= DEST_LOCATION.latitude){ + bound = LatLngBounds(southwest: SOURCE_LOCATION, northeast: DEST_LOCATION); + }else{ + bound = LatLngBounds(southwest: DEST_LOCATION, northeast: SOURCE_LOCATION); + } + + if(bound == null) + return; + + CameraUpdate camera = CameraUpdate.newLatLngBounds(bound, 50); + final GoogleMapController controller = await _controller.future; + controller.animateCamera(camera); + } + } + + bool showSrcMarkerTitle = false; + onSourceMarkerTap() async{ + // showSrcMarkerTitle = !showSrcMarkerTitle; + } + + bool showDestMarkerTitle = false; + onDestinationMarkerTap() async{ + // showDestMarkerTitle = !showDestMarkerTitle; + // Marker m = _markers.firstWhere((m) => m.markerId.value == 'destPin'); + // if(showDestMarkerTitle){ + // } + } +} diff --git a/lib/uitl/translations_delegate_base.dart b/lib/uitl/translations_delegate_base.dart index 557dc6f7..9ed7b478 100644 --- a/lib/uitl/translations_delegate_base.dart +++ b/lib/uitl/translations_delegate_base.dart @@ -563,6 +563,8 @@ class TranslationBase { String get shippedMethod => localizedValues['shippedMethod'][locale.languageCode]; String get orderDetail => localizedValues['orderDetail'][locale.languageCode]; String get deliveryDriverTrack => localizedValues['DeliveryDriverTrack'][locale.languageCode]; + String get deliveryLocation => localizedValues['DeliveryLocation'][locale.languageCode]; + String get driver => localizedValues['Driver'][locale.languageCode]; String get subtotal => localizedValues['subtotal'][locale.languageCode]; String get shipping => localizedValues['shipping'][locale.languageCode]; String get shipBy => localizedValues['shipBy'][locale.languageCode]; From b9a12341d5c3cc2d351b7b347e56201f0d2a7adc Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Wed, 10 Mar 2021 09:46:18 +0300 Subject: [PATCH 04/26] updates & fixes --- lib/config/localized_values.dart | 4 + lib/core/service/client/base_app_client.dart | 75 +-- lib/pages/landing/home_page.dart | 31 +- lib/pages/pharmacies/product-brands.dart | 2 + lib/pages/pharmacies/product_detail.dart | 460 ++++++++++-------- .../screens/cart-order-preview.dart | 10 +- lib/uitl/translations_delegate_base.dart | 1 + 7 files changed, 335 insertions(+), 248 deletions(-) diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index f6257ae8..da5809e5 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -1954,4 +1954,8 @@ const Map localizedValues = { }, "order-overview": {"en": "Order Overview", "ar": "ملخص الطلب"}, "shipping-address": {"en": "Delivery Address", "ar": "عنوان التوصيل"}, + "pharmacy-relogin": { + "en": "Your session has timed out, Please try again", + "ar": "انتهت مهلة جلسة الخاص بها. يرجى المحاولة مرة أخرى" + }, }; diff --git a/lib/core/service/client/base_app_client.dart b/lib/core/service/client/base_app_client.dart index abfa7594..fab6d8fd 100644 --- a/lib/core/service/client/base_app_client.dart +++ b/lib/core/service/client/base_app_client.dart @@ -7,6 +7,8 @@ import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; import 'package:diplomaticquarterapp/models/Appointments/toDoCountProviderModel.dart'; import 'package:diplomaticquarterapp/pages/appUpdatePage/app_update_page.dart'; import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; +import 'package:diplomaticquarterapp/uitl/app_toast.dart'; +import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/uitl/utils.dart'; import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; import 'package:flutter/cupertino.dart'; @@ -293,7 +295,13 @@ class BaseAppClient { print("statusCode :$statusCode"); if (statusCode < 200 || statusCode >= 400 || json == null) { - onFailure('Error While Fetching data', statusCode); + if (statusCode == 401) { + AppToast.showErrorToast( + message: TranslationBase.of(AppGlobal.context).pharmacyRelogin); + Navigator.of(AppGlobal.context).pushNamed(HOME); + } else { + onFailure('Error While Fetching data', statusCode); + } } else { var parsed = json.decode(response.body.toString()); onSuccess(parsed, statusCode); @@ -386,13 +394,12 @@ class BaseAppClient { return params; } - pharmacyPost(String endPoint, {Map body, - Function(dynamic response, int statusCode) onSuccess, - Function(String error, int statusCode) onFailure, - bool isAllowAny = false, - bool isExternal = false}) async { + Function(dynamic response, int statusCode) onSuccess, + Function(String error, int statusCode) onFailure, + bool isAllowAny = false, + bool isExternal = false}) async { String url; if (isExternal) { url = endPoint; @@ -404,13 +411,13 @@ class BaseAppClient { if (!isExternal) { String token = await sharedPref.getString(TOKEN); var languageID = - await sharedPref.getStringWithDefaultValue(APP_LANGUAGE, 'ar'); + await sharedPref.getStringWithDefaultValue(APP_LANGUAGE, 'ar'); var user = await sharedPref.getObject(USER_PROFILE); if (body.containsKey('SetupID')) { body['SetupID'] = body.containsKey('SetupID') ? body['SetupID'] != null - ? body['SetupID'] - : SETUP_ID + ? body['SetupID'] + : SETUP_ID : SETUP_ID; } @@ -422,17 +429,17 @@ class BaseAppClient { body['generalid'] = GENERAL_ID; body['PatientOutSA'] = body.containsKey('PatientOutSA') ? body['PatientOutSA'] != null - ? body['PatientOutSA'] - : PATIENT_OUT_SA + ? body['PatientOutSA'] + : PATIENT_OUT_SA : PATIENT_OUT_SA; if (body.containsKey('isDentalAllowedBackend')) { body['isDentalAllowedBackend'] = - body.containsKey('isDentalAllowedBackend') - ? body['isDentalAllowedBackend'] != null - ? body['isDentalAllowedBackend'] - : IS_DENTAL_ALLOWED_BACKEND - : IS_DENTAL_ALLOWED_BACKEND; + body.containsKey('isDentalAllowedBackend') + ? body['isDentalAllowedBackend'] != null + ? body['isDentalAllowedBackend'] + : IS_DENTAL_ALLOWED_BACKEND + : IS_DENTAL_ALLOWED_BACKEND; } body['DeviceTypeID'] = DeviceTypeID; @@ -440,18 +447,18 @@ class BaseAppClient { if (!body.containsKey('IsPublicRequest')) { body['PatientType'] = body.containsKey('PatientType') ? body['PatientType'] != null - ? body['PatientType'] - : user['PatientType'] != null - ? user['PatientType'] - : PATIENT_TYPE + ? body['PatientType'] + : user['PatientType'] != null + ? user['PatientType'] + : PATIENT_TYPE : PATIENT_TYPE; body['PatientTypeID'] = body.containsKey('PatientTypeID') ? body['PatientTypeID'] != null - ? body['PatientTypeID'] - : user['PatientType'] != null - ? user['PatientType'] - : PATIENT_TYPE_ID + ? body['PatientTypeID'] + : user['PatientType'] != null + ? user['PatientType'] + : PATIENT_TYPE_ID : PATIENT_TYPE_ID; if (user != null) { body['TokenID'] = token; @@ -469,13 +476,12 @@ class BaseAppClient { var ss = json.encode(body); if (await Utils.checkConnection()) { - final response = await http.post(url.trim(), - body: json.encode(body), - headers: { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'Statictoken': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9', - }); + final response = + await http.post(url.trim(), body: json.encode(body), headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Statictoken': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9', + }); final int statusCode = response.statusCode; print("statusCode :$statusCode"); if (statusCode < 200 || statusCode >= 400 || json == null) { @@ -515,12 +521,11 @@ class BaseAppClient { parsed['IsAuthenticated']) { if (parsed['message'] == null && parsed['ErrorEndUserMessage'] == null) { - if(parsed['ErrorSearchMsg'] == null ){ + if (parsed['ErrorSearchMsg'] == null) { onFailure("Server Error found with no available message", statusCode); - }else { - onFailure(parsed['ErrorSearchMsg'], - statusCode); + } else { + onFailure(parsed['ErrorSearchMsg'], statusCode); } } else { onFailure( diff --git a/lib/pages/landing/home_page.dart b/lib/pages/landing/home_page.dart index 452c315c..c2f96194 100644 --- a/lib/pages/landing/home_page.dart +++ b/lib/pages/landing/home_page.dart @@ -1,6 +1,8 @@ import 'package:diplomaticquarterapp/config/size_config.dart'; import 'package:diplomaticquarterapp/core/viewModels/dashboard_view_model.dart'; +import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/pharmacy_module_view_model.dart'; import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; +import 'package:diplomaticquarterapp/locator.dart'; import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/ComprehensiveMedicalCheckup/cmc_page.dart'; import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/HomeHealthCare/home_health_care_page.dart'; import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/all_habib_medical_service_page.dart'; @@ -11,6 +13,7 @@ import 'package:diplomaticquarterapp/pages/base/base_view.dart'; import 'package:diplomaticquarterapp/pages/livecare/livecare_home.dart'; import 'package:diplomaticquarterapp/pages/paymentService/payment_service.dart'; import 'package:diplomaticquarterapp/uitl/date_uitl.dart'; +import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/widgets/data_display/text.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; @@ -33,6 +36,9 @@ class HomePage extends StatefulWidget { } class _HomePageState extends State { + PharmacyModuleViewModel pharmacyModuleViewModel = + locator(); + @override Widget build(BuildContext context) { ProjectViewModel projectViewModel = Provider.of(context); @@ -503,8 +509,7 @@ class _HomePageState extends State { ), if (projectViewModel.havePrivilege(65)) DashboardItem( - onTap: () => Navigator.push( - context, FadePage(page: LandingPagePharmacy())), + onTap: () => getPharmacyToken(model), child: Center( child: Padding( padding: const EdgeInsets.all(15.0), @@ -799,10 +804,24 @@ class _HomePageState extends State { ); } - // openBrowser() { - // InAppBrowser browser = new InAppBrowser(); - // browser.openUrl(url: "https://uat.hmgwebservices.com/epharmacy/checkout/OpcCompleteRedirectionPaymentClientbyOrder?orderID=ca9dd276-0a20-4924-a768-fafa9a855ef1&&CustomerId=1367368"); - // } + getPharmacyToken(DashboardViewModel model) async { + if(!model.isLogin) { + Navigator.push(context, FadePage(page: LandingPagePharmacy())); + } else { + GifLoaderDialogUtils.showMyDialog(context); + await pharmacyModuleViewModel.generatePharmacyToken().then((value) async { + if (pharmacyModuleViewModel.error.isNotEmpty) { + await pharmacyModuleViewModel.createUser().then((value) { + GifLoaderDialogUtils.hideDialog(context); + Navigator.push(context, FadePage(page: LandingPagePharmacy())); + }); + } else { + GifLoaderDialogUtils.hideDialog(context); + Navigator.push(context, FadePage(page: LandingPagePharmacy())); + } + }); + } + } navigateToCovidDriveThru() { Navigator.push(context, FadePage(page: CovidDrivethruLocation())); diff --git a/lib/pages/pharmacies/product-brands.dart b/lib/pages/pharmacies/product-brands.dart index 945fbda1..e2fefab0 100644 --- a/lib/pages/pharmacies/product-brands.dart +++ b/lib/pages/pharmacies/product-brands.dart @@ -28,6 +28,7 @@ class _ProductBrandsPageState extends State { @override Widget build(BuildContext context) { return BaseView( + allowAny: true, onModelReady: (model) => model.getBrandsData(), builder: (_, model, wi) => AppScaffold( appBarTitle: 'Brands page', @@ -142,6 +143,7 @@ class _ProductBrandsPageState extends State { topBrand(BuildContext context) { return BaseView( + allowAny: true, onModelReady: (model) => model.getTopBrandsData(), builder: (_, model, wi) => GridView.count( crossAxisCount: 4, diff --git a/lib/pages/pharmacies/product_detail.dart b/lib/pages/pharmacies/product_detail.dart index c119f468..bd776355 100644 --- a/lib/pages/pharmacies/product_detail.dart +++ b/lib/pages/pharmacies/product_detail.dart @@ -1,23 +1,22 @@ import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; import 'package:diplomaticquarterapp/core/model/pharmacies/PharmacyProduct.dart'; -import 'package:diplomaticquarterapp/core/model/pharmacies/recommendedProduct_model.dart'; import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/pharmacy_module_view_model.dart'; import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/product_detail_view_model.dart'; import 'package:diplomaticquarterapp/pages/base/base_view.dart'; -import 'package:diplomaticquarterapp/pages/login/welcome.dart'; +import 'package:diplomaticquarterapp/pages/pharmacies/compare-list.dart'; +import 'package:diplomaticquarterapp/uitl/app_toast.dart'; import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/widgets/data_display/text.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scafold_detail_page.dart'; import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; import 'package:flutter/material.dart'; -import 'package:diplomaticquarterapp/widgets/others/app_scafold_detail_page.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:provider/provider.dart'; import 'package:rating_bar/rating_bar.dart'; -import 'package:diplomaticquarterapp/uitl/app_toast.dart'; + import 'screens/cart-order-page.dart'; -import 'package:diplomaticquarterapp/pages/pharmacies/compare-list.dart'; int price = 0; var languageID; @@ -30,7 +29,9 @@ PharmacyProduct specificationData; class ProductDetailPage extends StatefulWidget { final PharmacyProduct product; + ProductDetailPage(this.product); + @override __ProductDetailPageState createState() => __ProductDetailPageState(); } @@ -42,8 +43,10 @@ class __ProductDetailPageState extends State { bool isAvailabilty = false; dynamic wishlistItems; var model; + // String ProductId="4561"; String productId = ""; + checkWishlist() async { GifLoaderDialogUtils.showMyDialog(context); ProductDetailViewModel x = new ProductDetailViewModel(); @@ -62,6 +65,7 @@ class __ProductDetailPageState extends State { GifLoaderDialogUtils.hideDialog(context); setState(() {}); } + void initState() { price = 1; specificationData = widget.product; @@ -613,21 +617,20 @@ class __ProductDetailPageState extends State { Container( width: 410, height: 50, - // margin: EdgeInsets.only(bottom: 5), + // margin: EdgeInsets.only(bottom: 5), color: Colors.white, child: Texts( TranslationBase.of(context).recommended, bold: true, ), ), - ], ), SingleChildScrollView( child: Container( color: Colors.white, child: Column( - // crossAxisAlignment: CrossAxisAlignment.start, + // crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, // mainAxisSize: MainAxisSize.min, children: [ @@ -636,208 +639,252 @@ class __ProductDetailPageState extends State { height: 210, margin: EdgeInsets.only(bottom: 75), padding: EdgeInsets.only(bottom: 5), - // margin: EdgeInsets.symmetric(horizontal: 6, vertical: 4), + // margin: EdgeInsets.symmetric(horizontal: 6, vertical: 4), child: BaseView( onModelReady: (model) => - model.getRecommendedProducts(widget.product.id.toString()), - builder: (_, model, wi) => - Container( + model.getRecommendedProducts( + widget.product.id.toString()), + builder: (_, model, wi) => Container( child: // Text(model.recommendedProductList[0].id), - model.recommendedProductList.length != null - ? Expanded( - child: ListView.builder( - scrollDirection: Axis.horizontal, - shrinkWrap: true, - physics: ScrollPhysics(), - // physics: NeverScrollableScrollPhysics(), - itemCount: model.recommendedProductList.length, - itemBuilder: (context, index) { - return Card( - elevation: 2, - shape: RoundedRectangleBorder( - side: BorderSide( - color: Colors.grey[300], width: 2), - borderRadius: BorderRadius.circular(10)), - margin: EdgeInsets.symmetric( - horizontal: 8, - vertical: 0, - ), - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.all( - Radius.circular(15), - ), - ), - padding: EdgeInsets.symmetric(horizontal: 4), - width: MediaQuery.of(context).size.width / 3, - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Stack(children: [ - Container( - child: Align( - alignment: Alignment.topRight, - child: //true - itemID.contains(model.recommendedProductList[index].id) - // !isInWishlist - ? IconButton( - icon: Icon(Icons - .favorite_border), - color: Colors.grey, - iconSize: 30, - onPressed: () { - setState(() { - addToWishlistFunction(itemID); - }); - }, - ) - : IconButton( - icon: Icon( - Icons.favorite), - color: Colors.red, - iconSize: 30, - onPressed: () { - setState(() { - deleteFromWishlistFunction(itemID); - }); - }, - ) -// + model.recommendedProductList.length != + null + ? Expanded( + child: ListView.builder( + scrollDirection: + Axis.horizontal, + shrinkWrap: true, + physics: ScrollPhysics(), + // physics: NeverScrollableScrollPhysics(), + itemCount: model + .recommendedProductList + .length, + itemBuilder: + (context, index) { + return Card( + elevation: 2, + shape: RoundedRectangleBorder( + side: BorderSide( + color: Colors + .grey[ + 300], + width: 2), + borderRadius: + BorderRadius + .circular( + 10)), + margin: EdgeInsets + .symmetric( + horizontal: 8, + vertical: 0, ), - ), - Container( - margin: EdgeInsets.fromLTRB( - 0, 16, 10, 16), - alignment: Alignment.center, + child: Container( + decoration: + BoxDecoration( + borderRadius: + BorderRadius + .all( + Radius.circular( + 15), + ), + ), + padding: EdgeInsets + .symmetric( + horizontal: + 4), + width: MediaQuery.of( + context) + .size + .width / + 3, + child: Column( + crossAxisAlignment: + CrossAxisAlignment + .start, + children: [ + Stack( + children: [ + Container( + child: Align( + alignment: Alignment.topRight, + child: //true + itemID.contains(model.recommendedProductList[index].id) + // !isInWishlist + ? IconButton( + icon: Icon(Icons.favorite_border), + color: Colors.grey, + iconSize: 30, + onPressed: () { + setState(() { + addToWishlistFunction(itemID); + }); + }, + ) + : IconButton( + icon: Icon(Icons.favorite), + color: Colors.red, + iconSize: 30, + onPressed: () { + setState(() { + deleteFromWishlistFunction(itemID); + }); + }, + ) +// + ), + ), + Container( + margin: EdgeInsets.fromLTRB( + 0, + 16, + 10, + 16), + alignment: + Alignment.center, // padding: EdgeInsets.only(left: 25, bottom: 20), - child: (model.recommendedProductList[index].images != null && - model.recommendedProductList[index].images.length > 0) - ? Image.network( - model.recommendedProductList[index].images[0].src.toString(), + child: (model.recommendedProductList[index].images != null && + model.recommendedProductList[index].images.length > 0) + ? Image.network( + model.recommendedProductList[index].images[0].src.toString(), // item.images[0].src, - fit: BoxFit.cover, - height: 60, - ) - : Image.asset( - "assets/images/no_image.png", - fit: BoxFit.cover, - height: 60, - ), - ), - Container( - width: model - .recommendedProductList[ - index] - .rxMessage != - null - ? MediaQuery.of(context) - .size - .width / - 5 - : 0, - padding: EdgeInsets.all(4), - decoration: BoxDecoration( - color: Color(0xffb23838), - borderRadius: BorderRadius.only( - topLeft: Radius.circular(6)), - ), - child: Texts( - model.recommendedProductList[index] - .rxMessage != - null - ? model - .recommendedProductList[ - index] - .rxMessage - : "", - color: Colors.white, - regular: true, - fontSize: 10, - fontWeight: FontWeight.w400, - ), - ), - ]), - Container( - margin: EdgeInsets.symmetric( - horizontal: 6, - vertical: 0, - ), - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - languageID == "ar" - ? model.recommendedProductList[index].namen - : model.recommendedProductList[index].name, - style: TextStyle( - color: Colors.black, - fontSize: 13.0, + fit: BoxFit.cover, + height: 60, + ) + : Image.asset( + "assets/images/no_image.png", + fit: BoxFit.cover, + height: 60, + ), + ), + Container( + width: model.recommendedProductList[index].rxMessage != + null + ? MediaQuery.of(context).size.width / + 5 + : 0, + padding: + EdgeInsets.all(4), + decoration: + BoxDecoration( + color: + Color(0xffb23838), + borderRadius: + BorderRadius.only(topLeft: Radius.circular(6)), + ), + child: + Texts( + model.recommendedProductList[index].rxMessage != null + ? model.recommendedProductList[index].rxMessage + : "", + color: + Colors.white, + regular: + true, + fontSize: + 10, + fontWeight: + FontWeight.w400, + ), + ), + ]), + Container( + margin: EdgeInsets + .symmetric( + horizontal: + 6, + vertical: 0, + ), + child: Column( + crossAxisAlignment: + CrossAxisAlignment + .start, + children: [ + Text( + languageID == + "ar" + ? model.recommendedProductList[index].namen + : model.recommendedProductList[index].name, + style: + TextStyle( + color: + Colors.black, + fontSize: + 13.0, // fontWeight: FontWeight.bold, - ), - ), - Padding( + ), + ), + Padding( // padding: const EdgeInsets.only(top: 15, bottom: 10), - padding: const EdgeInsets.only( - top: 10, bottom: 5), - child: Texts( - "SAR ${model.recommendedProductList[index].price}", - bold: true, - fontSize: 14, - ), - ), - ], - ), - ), - Row( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Container( - padding: - EdgeInsets.only(right: 10), + padding: const EdgeInsets.only( + top: + 10, + bottom: + 5), + child: + Texts( + "SAR ${model.recommendedProductList[index].price}", + bold: + true, + fontSize: + 14, + ), + ), + ], + ), + ), + Row( + crossAxisAlignment: + CrossAxisAlignment + .start, + children: < + Widget>[ + Container( + padding: + EdgeInsets.only(right: 10), // margin: EdgeInsets.only(left: 5), - child: Align( - alignment: Alignment.topLeft, - child: RatingBar.readOnly( - initialRating: model - .recommendedProductList[ - index] - .approvedRatingSum - .toDouble(), + child: + Align( + alignment: + Alignment.topLeft, + child: + RatingBar.readOnly( + initialRating: + model.recommendedProductList[index].approvedRatingSum.toDouble(), // initialRating: productRate, - size: 13.0, - filledColor: - Colors.yellow[700], - emptyColor: Colors.grey[500], - isHalfAllowed: true, - halfFilledIcon: - Icons.star_half, - filledIcon: Icons.star, - emptyIcon: Icons.star, - ), - ), - ), - Texts( - "(${model.recommendedProductList[index].approvedTotalReviews.toString()})", + size: + 13.0, + filledColor: + Colors.yellow[700], + emptyColor: + Colors.grey[500], + isHalfAllowed: + true, + halfFilledIcon: + Icons.star_half, + filledIcon: + Icons.star, + emptyIcon: + Icons.star, + ), + ), + ), + Texts( + "(${model.recommendedProductList[index].approvedTotalReviews.toString()})", // bold: true, - fontSize: 12, + fontSize: + 12, + ), + ]), + ], ), - ]), - ], - ), - ), - ); - }), - ) - : Container( + ), + ); + }), + ) + : Container( // child: Text("NO DATA"), - ), - ) - - ), + ), + )), ), ], ), @@ -1341,8 +1388,10 @@ class footerWidget extends StatefulWidget { final int minQuantity; final int quantityLimit; final PharmacyProduct item; + footerWidget(this.isAvailble, this.maxQuantity, this.minQuantity, this.quantityLimit, this.item); + @override _footerWidgetState createState() => _footerWidgetState(); } @@ -1350,6 +1399,7 @@ class footerWidget extends StatefulWidget { class _footerWidgetState extends State { double quantityUI = 70; bool showUI = false; + @override Widget build(BuildContext context) { return Container( @@ -1752,7 +1802,7 @@ class _footerWidgetState extends State { ) : InkWell( onTap: () { - addToCartFunction(price, widget.item.id); + addToCartFunction(price, widget.item.id, context); }, child: Container( alignment: Alignment.center, @@ -1792,11 +1842,10 @@ class _footerWidgetState extends State { : InkWell( onTap: () { print('buy now'); - addToCartFunction(price, widget.item.id); + addToCartFunction(price, widget.item.id, context); Navigator.push( context, - FadePage(page: - CartOrderPage()), + FadePage(page: CartOrderPage()), ); }, child: Container( @@ -1824,7 +1873,9 @@ class _footerWidgetState extends State { class productNameAndPrice extends StatefulWidget { BuildContext context; PharmacyProduct item; + productNameAndPrice(this.context, this.item); + @override _productNameAndPriceState createState() => _productNameAndPriceState(); } @@ -2014,9 +2065,12 @@ getSpecificationData(itemID) async { specificationData = await x.productSpecificationData(itemID); } -addToCartFunction(quantity, itemID) async { +addToCartFunction(quantity, itemID, BuildContext context) async { + GifLoaderDialogUtils.showMyDialog(context); ProductDetailViewModel x = new ProductDetailViewModel(); - await x.addToCartData(quantity, itemID); + await x.addToCartData(quantity, itemID).then((value) { + GifLoaderDialogUtils.hideDialog(context); + }); } notifyMeWhenAvailable(context, itemId) async { @@ -2071,7 +2125,7 @@ settingModalBottomSheet(context) { title: Text('Add to cart'), onTap: () => { if (price > 0) - {addToCartFunction(price, itemID)} + {addToCartFunction(price, itemID, context)} else { AppToast.showErrorToast( diff --git a/lib/pages/pharmacies/screens/cart-order-preview.dart b/lib/pages/pharmacies/screens/cart-order-preview.dart index e0c062fa..7555587a 100644 --- a/lib/pages/pharmacies/screens/cart-order-preview.dart +++ b/lib/pages/pharmacies/screens/cart-order-preview.dart @@ -4,25 +4,25 @@ import 'package:diplomaticquarterapp/core/model/pharmacies/payment-checkout-data import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/OrderPreviewViewModel.dart'; import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; import 'package:diplomaticquarterapp/pages/base/base_view.dart'; -import 'package:diplomaticquarterapp/pages/pharmacies/screens/address-select-page.dart'; import 'package:diplomaticquarterapp/pages/pharmacies/screens/payment-method-select-page.dart'; -import 'package:diplomaticquarterapp/pages/pharmacies/screens/pharmacy_module_page.dart'; import 'package:diplomaticquarterapp/pages/pharmacies/widgets/ProductOrderPreviewItem.dart'; import 'package:diplomaticquarterapp/pages/pharmacy/pharmacyAddresses/PharmacyAddresses.dart'; import 'package:diplomaticquarterapp/uitl/app_toast.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/widgets/data_display/text.dart'; +import 'package:diplomaticquarterapp/widgets/in_app_browser/InAppBrowser.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:flutter/scheduler.dart'; class OrderPreviewPage extends StatelessWidget { final List addresses; OrderPreviewPage(this.addresses); + MyInAppBrowser browser; + @override Widget build(BuildContext context) { final mediaQuery = MediaQuery.of(context); @@ -783,7 +783,9 @@ class PaymentBottomWidget extends StatelessWidget { ? () async { await model.makeOrder(); if (model.state != ViewState.Idle) { - AppToast.showSuccessToast(message: "Order has been placed successfully!!"); + AppToast.showSuccessToast( + message: + "Order has been placed successfully!!"); } else { AppToast.showErrorToast(message: model.error); } diff --git a/lib/uitl/translations_delegate_base.dart b/lib/uitl/translations_delegate_base.dart index 47c78b79..f5ad16ab 100644 --- a/lib/uitl/translations_delegate_base.dart +++ b/lib/uitl/translations_delegate_base.dart @@ -1570,6 +1570,7 @@ class TranslationBase { String get shippingAddresss => localizedValues["shipping-address"][locale.languageCode]; String get covidAlert => localizedValues["covid-alert"][locale.languageCode]; + String get pharmacyRelogin => localizedValues["pharmacy-relogin"][locale.languageCode]; } class TranslationBaseDelegate extends LocalizationsDelegate { From 74dd2745028971d4ea83a5bd7b09f3b7f19951d2 Mon Sep 17 00:00:00 2001 From: mosazaid Date: Wed, 10 Mar 2021 10:58:10 +0200 Subject: [PATCH 05/26] working on pharmacy some fixes on cart page and request body --- lib/core/service/client/base_app_client.dart | 207 +++- .../parmacyModule/order-preview-service.dart | 65 +- .../pharmacyModule/OrderPreviewViewModel.dart | 19 +- .../order_model_view_model.dart | 5 +- .../pharmacy_module_view_model.dart | 5 +- .../pharmacies/screens/cart-order-page.dart | 116 +- .../screens/cart-order-preview.dart | 1037 +++++++++-------- .../pharmacies/widgets/ProductOrderItem.dart | 151 ++- 8 files changed, 980 insertions(+), 625 deletions(-) diff --git a/lib/core/service/client/base_app_client.dart b/lib/core/service/client/base_app_client.dart index abfa7594..eb6e6850 100644 --- a/lib/core/service/client/base_app_client.dart +++ b/lib/core/service/client/base_app_client.dart @@ -31,6 +31,7 @@ AuthenticatedUserObject authenticatedUserObject = VitalSignService _vitalSignService = locator(); class BaseAppClient { + post(String endPoint, {Map body, Function(dynamic response, int statusCode) onSuccess, @@ -132,7 +133,198 @@ class BaseAppClient { if (statusCode < 200 || statusCode >= 400 || json == null) { onFailure('Error While Fetching data', statusCode); } else { - var parsed = json.decode(response.body.toString()); + // var parsed = json.decode(response.body.toString()); + var parsed = json.decode(utf8.decode(response.bodyBytes)); + if (parsed['Response_Message'] != null) { + onSuccess(parsed, statusCode); + } else { + if (parsed['ErrorType'] == 4) { + navigateToAppUpdate( + AppGlobal.context, parsed['ErrorEndUserMessage']); + } + if (isAllowAny) { + onSuccess(parsed, statusCode); + } else if (parsed['IsAuthenticated'] == null) { + if (parsed['isSMSSent'] == true) { + onSuccess(parsed, statusCode); + } else if (parsed['MessageStatus'] == 1) { + onSuccess(parsed, statusCode); + } else if (parsed['Result'] == 'OK') { + onSuccess(parsed, statusCode); + } else { + if (parsed != null) { + onSuccess(parsed, statusCode); + } else { + onFailure( + parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], + statusCode); + logout(); + } + } + } else if (parsed['MessageStatus'] == 1 || + parsed['SMSLoginRequired'] == true) { + onSuccess(parsed, statusCode); + } else if (parsed['MessageStatus'] == 2 && + parsed['IsAuthenticated']) { + if (parsed['SameClinicApptList'] != null) { + onSuccess(parsed, statusCode); + } else { + if (parsed['message'] == null && + parsed['ErrorEndUserMessage'] == null) { + if (parsed['ErrorSearchMsg'] == null) { + onFailure("Server Error found with no available message", + statusCode); + } else { + onFailure(parsed['ErrorSearchMsg'], statusCode); + } + } else { + onFailure( + parsed['message'] ?? + parsed['ErrorEndUserMessage'] ?? + parsed['ErrorMessage'], + statusCode); + } + } + } else if (!parsed['IsAuthenticated']) { + await logout(); + + //helpers.showErrorToast('Your session expired Please login agian'); + } else { + if (parsed['SameClinicApptList'] != null) { + onSuccess(parsed, statusCode); + } else { + if (parsed['message'] != null) { + onFailure(parsed['message'] ?? parsed['message'], statusCode); + } else { + onFailure( + parsed['ErrorEndUserMessage'] ?? parsed['ErrorMessage'], + statusCode); + } + } + } + } + } + } else { + onFailure('Please Check The Internet Connection', -1); + } + } catch (e) { + print(e); + onFailure(e.toString(), -1); + } + } + + postPharmacy(String endPoint, + {Map body, + Function(dynamic response, int statusCode) onSuccess, + Function(String error, int statusCode) onFailure, + bool isAllowAny = false, + bool isExternal = false}) async { + + var token = await sharedPref.getString(PHARMACY_AUTORZIE_TOKEN); + var user = await sharedPref.getObject(USER_PROFILE); + String url; + if (isExternal) { + url = endPoint; + } else { + url = PHARMACY_BASE_URL + endPoint; + } + try { + //Map profile = await sharedPref.getObj(DOCTOR_PROFILE); + var pharmacyToken = await sharedPref.getString(PHARMACY_AUTORZIE_TOKEN); + var user = await sharedPref.getObject(USER_PROFILE); + Map headers = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Authorization': token ?? '', + 'Mobilenumber': user != null + ? getPhoneNumberWithoutZero(user['MobileNumber'].toString()) + : "", + 'Statictoken': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9', + 'Username': user != null ? user['PatientID'].toString() : "", + }; + if (!isExternal) { + String token = await sharedPref.getString(TOKEN); + var languageID = + await sharedPref.getStringWithDefaultValue(APP_LANGUAGE, 'ar'); + if (body.containsKey('SetupID')) { + body['SetupID'] = body.containsKey('SetupID') + ? body['SetupID'] != null + ? body['SetupID'] + : SETUP_ID + : SETUP_ID; + } + + body['VersionID'] = VERSION_ID; + body['Channel'] = CHANNEL; + body['LanguageID'] = languageID == 'ar' ? 1 : 2; + + body['IPAdress'] = IP_ADDRESS; + body['generalid'] = GENERAL_ID; + body['PatientOutSA'] = body.containsKey('PatientOutSA') + ? body['PatientOutSA'] != null + ? body['PatientOutSA'] + : PATIENT_OUT_SA + : PATIENT_OUT_SA; + + if (body.containsKey('isDentalAllowedBackend')) { + body['isDentalAllowedBackend'] = + body.containsKey('isDentalAllowedBackend') + ? body['isDentalAllowedBackend'] != null + ? body['isDentalAllowedBackend'] + : IS_DENTAL_ALLOWED_BACKEND + : IS_DENTAL_ALLOWED_BACKEND; + } + + body['DeviceTypeID'] = DeviceTypeID; + + if (!body.containsKey('IsPublicRequest')) { + body['PatientType'] = body.containsKey('PatientType') + ? body['PatientType'] != null + ? body['PatientType'] + : user['PatientType'] != null + ? user['PatientType'] + : PATIENT_TYPE + : PATIENT_TYPE; + + body['PatientTypeID'] = body.containsKey('PatientTypeID') + ? body['PatientTypeID'] != null + ? body['PatientTypeID'] + : user['PatientType'] != null + ? user['PatientType'] + : PATIENT_TYPE_ID + : PATIENT_TYPE_ID; + if (user != null) { + body['TokenID'] = token; + body['PatientID'] = body['PatientID'] != null + ? body['PatientID'] + : user['PatientID']; + body['PatientOutSA'] = user['OutSA']; + body['SessionID'] = SESSION_ID; //getSe + headers = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Authorization': pharmacyToken, + 'Mobilenumber': user['MobileNumber'].toString(), + 'Statictoken': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9', + 'Username': user['PatientID'].toString(), + }; + } + } + } + + print("URL : $url"); + print("Body : ${json.encode(body)}"); + + if (await Utils.checkConnection()) { + final response = await http.post(url.trim(), + body: json.encode(body), headers: headers); + final int statusCode = response.statusCode; + print("statusCode :$statusCode"); + if (statusCode < 200 || statusCode >= 400 || json == null) { + onFailure('Error While Fetching data', statusCode); + } else { + // var parsed = json.decode(response.body.toString()); + var parsed = json.decode(utf8.decode(response.bodyBytes)); if (parsed['Response_Message'] != null) { onSuccess(parsed, statusCode); } else { @@ -248,7 +440,8 @@ class BaseAppClient { if (statusCode < 200 || statusCode >= 400 || json == null) { onFailure('Error While Fetching data', statusCode); } else { - var parsed = json.decode(response.body.toString()); + // var parsed = json.decode(response.body.toString()); + var parsed = json.decode(utf8.decode(response.bodyBytes)); onSuccess(parsed, statusCode); } } else { @@ -280,7 +473,7 @@ class BaseAppClient { if (await Utils.checkConnection()) { final response = await http.get(url.trim(), headers: { - 'Content-Type': 'application/json', + 'Content-Type': 'text/html; charset=utf-8', 'Accept': 'application/json', 'Authorization': token ?? '', 'Mobilenumber': user != null @@ -295,8 +488,9 @@ class BaseAppClient { if (statusCode < 200 || statusCode >= 400 || json == null) { onFailure('Error While Fetching data', statusCode); } else { - var parsed = json.decode(response.body.toString()); - onSuccess(parsed, statusCode); + // var parsed = json.decode(response.body.toString()); + var bodyUtf = json.decode(utf8.decode(response.bodyBytes)); + onSuccess(bodyUtf, statusCode); } } else { onFailure('Please Check The Internet Connection', -1); @@ -481,7 +675,8 @@ class BaseAppClient { if (statusCode < 200 || statusCode >= 400 || json == null) { onFailure('Error While Fetching data', statusCode); } else { - var parsed = json.decode(response.body.toString()); + // var parsed = json.decode(response.body.toString()); + var parsed = json.decode(utf8.decode(response.bodyBytes)); if (parsed['Response_Message'] != null) { onSuccess(parsed, statusCode); } else { diff --git a/lib/core/service/parmacyModule/order-preview-service.dart b/lib/core/service/parmacyModule/order-preview-service.dart index 18cfa87e..0721bf59 100644 --- a/lib/core/service/parmacyModule/order-preview-service.dart +++ b/lib/core/service/parmacyModule/order-preview-service.dart @@ -3,6 +3,7 @@ import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; import 'package:diplomaticquarterapp/core/model/pharmacies/Addresses.dart'; import 'package:diplomaticquarterapp/core/model/pharmacies/LacumAccountInformation.dart'; import 'package:diplomaticquarterapp/core/model/pharmacies/ShoppingCart.dart'; +import 'package:diplomaticquarterapp/core/model/pharmacies/order_detail.dart'; import 'package:diplomaticquarterapp/core/model/pharmacies/payment-checkout-data.dart'; import 'package:diplomaticquarterapp/core/service/base_service.dart'; import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/OrderPreviewViewModel.dart'; @@ -15,6 +16,7 @@ class OrderPreviewService extends BaseService { List addresses = List(); LacumAccountInformation lacumInformation; LacumAccountInformation lacumGroupInformation; + List orderList = List(); Future getAddresses() async { var customerId = await sharedPref.getString(PHARMACY_CUSTOMER_ID); @@ -42,13 +44,14 @@ class OrderPreviewService extends BaseService { dynamic localRes; hasError = false; try { - await baseAppClient.getPharmacy("$GET_SHIPPING_OPTIONS$customerId/${selectedAddress.id}", - onSuccess: (dynamic response, int statusCode) { - localRes = response['shipping_option'][0]; - }, onFailure: (String error, int statusCode) { - hasError = true; - super.error = error; - }, queryParams: queryParams); + await baseAppClient + .getPharmacy("$GET_SHIPPING_OPTIONS$customerId/${selectedAddress.id}", + onSuccess: (dynamic response, int statusCode) { + localRes = response['shipping_option'][0]; + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, queryParams: queryParams); } catch (error) { throw error; } @@ -89,7 +92,7 @@ class OrderPreviewService extends BaseService { Map body = Map(); body["shopping_cart_item"] = choppingCartObject; - await baseAppClient.post("$GET_SHOPPING_CART$productId", + await baseAppClient.postPharmacy("$GET_SHOPPING_CART$productId", onSuccess: (response, statusCode) async { localRes = response; }, onFailure: (String error, int statusCode) { @@ -125,8 +128,9 @@ class OrderPreviewService extends BaseService { super.error = ""; dynamic localRes; - await baseAppClient.getPharmacy("$DELETE_SHOPPING_CART_ALL$customerId/ShoppingCart", - onSuccess: (response, statusCode) async { + await baseAppClient + .getPharmacy("$DELETE_SHOPPING_CART_ALL$customerId/ShoppingCart", + onSuccess: (response, statusCode) async { localRes = response; }, onFailure: (String error, int statusCode) { hasError = true; @@ -167,23 +171,24 @@ class OrderPreviewService extends BaseService { try { await baseAppClient.post(GET_LACUM_GROUP_INFORMATION, onSuccess: (response, statusCode) async { - lacumGroupInformation = LacumAccountInformation.fromJson(response); - }, onFailure: (String error, int statusCode) { - hasError = true; - super.error = error; - }, body: body); + lacumGroupInformation = LacumAccountInformation.fromJson(response); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: body); } catch (error) { throw error; } } - Future makeOrder(PaymentCheckoutData paymentCheckoutData, List shoppingCarts) async { + Future makeOrder(PaymentCheckoutData paymentCheckoutData, + List shoppingCarts) async { paymentCheckoutData.address.isChecked = true; hasError = false; super.error = ""; var languageID = - await sharedPref.getStringWithDefaultValue(APP_LANGUAGE, 'en'); + await sharedPref.getStringWithDefaultValue(APP_LANGUAGE, 'en'); var customerId = await sharedPref.getString(PHARMACY_CUSTOMER_ID); Map orderBody = Map(); @@ -192,10 +197,15 @@ class OrderPreviewService extends BaseService { orderBody['billing_address'] = paymentCheckoutData.address; orderBody['pick_up_in_store'] = false; orderBody['payment_method_system_name'] = "Payments.PayFort"; - orderBody['shipping_method'] = languageID == 'ar' ? paymentCheckoutData.shippingOption.namen : paymentCheckoutData.shippingOption.name ; - orderBody['shipping_rate_computation_method_system_name'] = paymentCheckoutData.shippingOption.shippingRateComputationMethodSystemName; - orderBody['customer_id'] = customerId; - orderBody['custom_values_xml'] = "PaymentOption:${getPaymentOptionName(paymentCheckoutData.paymentOption)}"; + orderBody['shipping_method'] = languageID == 'ar' + ? paymentCheckoutData.shippingOption.namen + : paymentCheckoutData.shippingOption.name; + orderBody['shipping_rate_computation_method_system_name'] = + paymentCheckoutData + .shippingOption.shippingRateComputationMethodSystemName; + orderBody['customer_id'] = int.parse(customerId); + orderBody['custom_values_xml'] = + "PaymentOption:${getPaymentOptionName(paymentCheckoutData.paymentOption)}"; orderBody['shippingOption'] = paymentCheckoutData.shippingOption; orderBody['shipping_address'] = paymentCheckoutData.address; orderBody['lakum_amount'] = paymentCheckoutData.usedLakumPoints; @@ -215,10 +225,15 @@ class OrderPreviewService extends BaseService { try { await baseAppClient.post(ORDER_SHOPPING_CART, onSuccess: (response, statusCode) async { - }, onFailure: (String error, int statusCode) { - hasError = true; - super.error = error; - }, body: body); + orderList.clear(); + response['orders'].forEach((item) { + orderList.add(OrderDetailModel.fromJson(item)); + print(response); + }); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: body); } catch (error) { throw error; } diff --git a/lib/core/viewModels/pharmacyModule/OrderPreviewViewModel.dart b/lib/core/viewModels/pharmacyModule/OrderPreviewViewModel.dart index 7272969b..1fa34ee2 100644 --- a/lib/core/viewModels/pharmacyModule/OrderPreviewViewModel.dart +++ b/lib/core/viewModels/pharmacyModule/OrderPreviewViewModel.dart @@ -5,8 +5,10 @@ import 'package:diplomaticquarterapp/core/model/pharmacies/LacumAccountInformati import 'package:diplomaticquarterapp/core/model/pharmacies/ShippingOption.dart'; import 'package:diplomaticquarterapp/core/model/pharmacies/ShoppingCart.dart'; import 'package:diplomaticquarterapp/core/model/pharmacies/ShoppingCartResponse.dart'; +import 'package:diplomaticquarterapp/core/model/pharmacies/order_detail.dart'; import 'package:diplomaticquarterapp/core/model/pharmacies/payment-checkout-data.dart'; import 'package:diplomaticquarterapp/core/service/parmacyModule/order-preview-service.dart'; +import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/pharmacy_module_view_model.dart'; import '../../../locator.dart'; import '../base_view_model.dart'; @@ -17,6 +19,11 @@ class OrderPreviewViewModel extends BaseViewModel { List get addresses => _orderService.addresses; LacumAccountInformation get lacumInformation => _orderService.lacumInformation; + List get orderListModel => _orderService.orderList; + + PharmacyModuleViewModel pharmacyModuleViewModel = + locator(); + ShoppingCartResponse cartResponse = ShoppingCartResponse(); PaymentCheckoutData paymentCheckoutData = PaymentCheckoutData(); double totalAdditionalShippingCharge = 0; @@ -32,7 +39,7 @@ class OrderPreviewViewModel extends BaseViewModel { } } - getShoppingCart() async { + Future getShoppingCart() async { setState(ViewState.Busy); await _orderService.getShoppingCart().then((res) { _handleGetShoppingCartResponse(res); @@ -48,20 +55,20 @@ class OrderPreviewViewModel extends BaseViewModel { } } - changeProductQuantity(ShoppingCart product) async { + Future changeProductQuantity(ShoppingCart product) async { setState(ViewState.Busy); await _orderService.changeProductQuantity(product.id, product).then((res) { _handleGetShoppingCartResponse(res); }); if (_orderService.hasError) { error = _orderService.error; - setState(ViewState.Error); + setState(ViewState.ErrorLocal); } else { setState(ViewState.Idle); } } - deleteProduct(ShoppingCart product) async { + Future deleteProduct(ShoppingCart product) async { setState(ViewState.Busy); await _orderService.deleteProduct(product.id).then((res) { _handleGetShoppingCartResponse(res); @@ -74,7 +81,7 @@ class OrderPreviewViewModel extends BaseViewModel { } } - deleteShoppingCart() async { + Future deleteShoppingCart() async { setState(ViewState.Busy); await _orderService.deleteShoppingCart().then((res) { _handleGetShoppingCartResponse(res); @@ -182,6 +189,8 @@ class OrderPreviewViewModel extends BaseViewModel { Future makeOrder() async { setState(ViewState.Busy); + await pharmacyModuleViewModel.generatePharmacyToken(); + await _orderService.makeOrder(paymentCheckoutData, cartResponse.shoppingCarts); if (_orderService.hasError) { error = _orderService.error; diff --git a/lib/core/viewModels/pharmacyModule/order_model_view_model.dart b/lib/core/viewModels/pharmacyModule/order_model_view_model.dart index 62bf00f4..208f8189 100644 --- a/lib/core/viewModels/pharmacyModule/order_model_view_model.dart +++ b/lib/core/viewModels/pharmacyModule/order_model_view_model.dart @@ -110,15 +110,16 @@ class OrderModelViewModel extends BaseViewModel { message: "Your review has been Submitted successfully"); } } + Future makeOrder() async { - setState(ViewState.Busy); + /* setState(ViewState.Busy); await _orderServices.makeOrder(paymentCheckoutData, cartResponse.shoppingCarts); if (_orderServices.hasError) { error = _orderServices.error; setState(ViewState.Error); } else { setState(ViewState.Idle); - } + }*/ } } diff --git a/lib/core/viewModels/pharmacyModule/pharmacy_module_view_model.dart b/lib/core/viewModels/pharmacyModule/pharmacy_module_view_model.dart index f38237e3..dcf09865 100644 --- a/lib/core/viewModels/pharmacyModule/pharmacy_module_view_model.dart +++ b/lib/core/viewModels/pharmacyModule/pharmacy_module_view_model.dart @@ -44,13 +44,14 @@ class PharmacyModuleViewModel extends BaseViewModel { // List get pharmacyPrescriptionsList => PharmacyProduct.pharmacyPrescriptionsList ; Future getPharmacyHomeData() async { - setState(ViewState.Busy); + await generatePharmacyToken(); + var data = await sharedPref.getObject(USER_PROFILE); var customerId = await sharedPref.getString(PHARMACY_CUSTOMER_ID); + setState(ViewState.Busy); if (authenticatedUserObject.isLogin && data != null && customerId == null) { await _pharmacyService.makeVerifyCustomer(data); - // here must call getShoppingCard() if (_pharmacyService.hasError) { error = _pharmacyService.error; setState(ViewState.Error); diff --git a/lib/pages/pharmacies/screens/cart-order-page.dart b/lib/pages/pharmacies/screens/cart-order-page.dart index cca6c1df..f672cc66 100644 --- a/lib/pages/pharmacies/screens/cart-order-page.dart +++ b/lib/pages/pharmacies/screens/cart-order-page.dart @@ -1,3 +1,4 @@ +import 'package:diplomaticquarterapp/core/enum/viewstate.dart'; import 'package:diplomaticquarterapp/core/model/pharmacies/Addresses.dart'; import 'package:diplomaticquarterapp/core/model/pharmacies/ShoppingCartResponse.dart'; import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/OrderPreviewViewModel.dart'; @@ -7,6 +8,7 @@ import 'package:diplomaticquarterapp/pages/pharmacies/screens/cart-order-preview import 'package:diplomaticquarterapp/pages/pharmacies/screens/pharmacy-terms-conditions-page.dart'; import 'package:diplomaticquarterapp/pages/pharmacies/widgets/ProductOrderItem.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; +import 'package:diplomaticquarterapp/uitl/utils.dart'; import 'package:diplomaticquarterapp/widgets/buttons/GestureIconButton.dart'; import 'package:diplomaticquarterapp/widgets/data_display/text.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; @@ -32,7 +34,7 @@ class CartOrderPage extends StatelessWidget { baseViewModel: model, backgroundColor: Colors.white, body: !(model.cartResponse.shoppingCarts == null || - model.cartResponse.shoppingCarts.length == 0) + model.cartResponse.shoppingCarts.length == 0) ? Container( height: height * 0.85, width: double.infinity, @@ -70,8 +72,16 @@ class CartOrderPage extends StatelessWidget { cart.shoppingCarts[index], () { print(cart.shoppingCarts[index] .quantity); - model.changeProductQuantity( - cart.shoppingCarts[index]); + model + .changeProductQuantity( + cart.shoppingCarts[index]) + .then((value) { + if (model.state == + ViewState.ErrorLocal) { + Utils.showErrorToast( + model.error); + } + }); }, () => model.deleteProduct( cart.shoppingCarts[index]))) @@ -246,64 +256,62 @@ class _OrderBottomWidgetState extends State { height: widget.height * 0.070, color: Color(0xffe6ffe0), padding: EdgeInsets.symmetric(horizontal: 4), - child: Expanded( - child: Row( - children: [ - InkWell( - onTap: () { - setState(() { - isAgree = !isAgree; - }); - }, - child: Container( - width: 25.0, - height: widget.height * 0.070, - decoration: new BoxDecoration( - color: !isAgree - ? Color(0xffeeeeee) - : Colors.green, - shape: BoxShape.circle, + child: Row( + children: [ + InkWell( + onTap: () { + setState(() { + isAgree = !isAgree; + }); + }, + child: Container( + width: 25.0, + height: widget.height * 0.070, + decoration: new BoxDecoration( + color: !isAgree + ? Color(0xffeeeeee) + : Colors.green, + shape: BoxShape.circle, + ), + child: !isAgree + ? null + : Padding( + padding: const EdgeInsets.all(0.0), + child: Icon( + Icons.check, + color: Colors.white, + size: 25, ), - child: !isAgree - ? null - : Padding( - padding: const EdgeInsets.all(0.0), - child: Icon( - Icons.check, - color: Colors.white, - size: 25, - ), - ), ), ), - Expanded( - child: Container( - padding: EdgeInsets.symmetric(horizontal: 4), - margin: const EdgeInsets.symmetric(vertical: 4), - child: Texts( - TranslationBase.of(context) - .pharmacyServiceTermsCondition, - fontSize: 13, - color: Colors.grey.shade800, - fontWeight: FontWeight.normal, - ), + ), + Expanded( + child: Container( + padding: EdgeInsets.symmetric(horizontal: 4), + margin: const EdgeInsets.symmetric(vertical: 4), + child: Texts( + TranslationBase.of(context) + .pharmacyServiceTermsCondition, + fontSize: 13, + color: Colors.grey.shade800, + fontWeight: FontWeight.normal, ), ), - InkWell( - onTap: () => { - Navigator.push(context, - FadePage(page: PharmacyTermsConditions())) - }, - child: Container( - child: Icon( - Icons.info, - size: 25, - color: Color(0xff005aff), - ), + ), + InkWell( + onTap: () => { + Navigator.push(context, + FadePage(page: PharmacyTermsConditions())) + }, + child: Container( + child: Icon( + Icons.info, + size: 25, + color: Color(0xff005aff), ), ), - ], - ), + ), + ], ), ), Container( diff --git a/lib/pages/pharmacies/screens/cart-order-preview.dart b/lib/pages/pharmacies/screens/cart-order-preview.dart index e0c062fa..7a726e7c 100644 --- a/lib/pages/pharmacies/screens/cart-order-preview.dart +++ b/lib/pages/pharmacies/screens/cart-order-preview.dart @@ -1,8 +1,11 @@ import 'package:diplomaticquarterapp/core/enum/viewstate.dart'; import 'package:diplomaticquarterapp/core/model/pharmacies/Addresses.dart'; +import 'package:diplomaticquarterapp/core/model/pharmacies/order_detail.dart'; import 'package:diplomaticquarterapp/core/model/pharmacies/payment-checkout-data.dart'; import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/OrderPreviewViewModel.dart'; import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; +import 'package:diplomaticquarterapp/models/Appointments/AppoimentAllHistoryResultList.dart'; +import 'package:diplomaticquarterapp/models/Authentication/authenticated_user.dart'; import 'package:diplomaticquarterapp/pages/base/base_view.dart'; import 'package:diplomaticquarterapp/pages/pharmacies/screens/address-select-page.dart'; import 'package:diplomaticquarterapp/pages/pharmacies/screens/payment-method-select-page.dart'; @@ -12,6 +15,7 @@ import 'package:diplomaticquarterapp/pages/pharmacy/pharmacyAddresses/PharmacyAd import 'package:diplomaticquarterapp/uitl/app_toast.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/widgets/data_display/text.dart'; +import 'package:diplomaticquarterapp/widgets/in_app_browser/InAppBrowser.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; import 'package:flutter/material.dart'; @@ -30,10 +34,13 @@ class OrderPreviewPage extends StatelessWidget { return BaseView( onModelReady: (model) => model.getShoppingCart(), - builder: (_, model, wi) => ChangeNotifierProvider.value( + builder: (_, model, wi) => + ChangeNotifierProvider.value( value: model.paymentCheckoutData, child: AppScaffold( - appBarTitle: "${TranslationBase.of(context).checkOut}", + appBarTitle: "${TranslationBase + .of(context) + .checkOut}", isShowAppBar: true, isPharmacy: true, isShowDecPage: false, @@ -56,18 +63,18 @@ class OrderPreviewPage extends StatelessWidget { ), Consumer( builder: (ctx, paymentData, _) => - paymentData.lacumInformation != null - ? Container( - child: Column( - children: [ - LakumWidget(model), - SizedBox( - height: 10, - ), - ], - ), - ) - : Container()), + paymentData.lacumInformation != null + ? Container( + child: Column( + children: [ + LakumWidget(model), + SizedBox( + height: 10, + ), + ], + ), + ) + : Container()), Container( color: Colors.white, width: double.infinity, @@ -76,7 +83,9 @@ class OrderPreviewPage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Texts( - TranslationBase.of(context).reviewOrder, + TranslationBase + .of(context) + .reviewOrder, fontSize: 14, fontWeight: FontWeight.bold, color: Colors.black, @@ -85,8 +94,10 @@ class OrderPreviewPage extends StatelessWidget { model.cartResponse.shoppingCarts != null ? model.cartResponse.shoppingCarts.length : 0, - (index) => ProductOrderPreviewItem( - model.cartResponse.shoppingCarts[index]), + (index) => + ProductOrderPreviewItem( + model.cartResponse + .shoppingCarts[index]), ), ], ), @@ -96,117 +107,140 @@ class OrderPreviewPage extends StatelessWidget { padding: EdgeInsets.all(8), child: model.cartResponse.subtotal != null ? Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Texts( - TranslationBase.of(context) - .orderSummary, - fontSize: 14, - fontWeight: FontWeight.bold, - color: Colors.black, - ), - SizedBox( - height: 20, - ), - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Texts( - "${TranslationBase.of(context).subtotal}", - fontSize: 14, - color: Colors.black, - fontWeight: FontWeight.w500, - ), - Texts( - "${TranslationBase.of(context).sar} ${(model.cartResponse.subtotal).toStringAsFixed(2)}", - fontSize: 14, - color: Colors.black, - fontWeight: FontWeight.w500, - ), - ], - ), - const Divider( - color: Color(0xFFD6D6D6), - height: 20, - thickness: 1, - indent: 0, - endIndent: 0, - ), - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Texts( - "${TranslationBase.of(context).shipping}", - fontSize: 14, - color: Colors.black, - fontWeight: FontWeight.w500, - ), - Texts( - "${TranslationBase.of(context).sar} ${(model.totalAdditionalShippingCharge).toStringAsFixed(2)}", - fontSize: 14, - color: Colors.black, - fontWeight: FontWeight.w500, - ), - ], - ), - const Divider( - color: Color(0xFFD6D6D6), - height: 20, - thickness: 1, - indent: 0, - endIndent: 0, - ), - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Texts( - "${TranslationBase.of(context).vat}", - fontSize: 14, - color: Colors.black, - fontWeight: FontWeight.w500, - ), - Texts( - "${TranslationBase.of(context).sar} ${(model.cartResponse.subtotalVatAmount).toStringAsFixed(2)}", - fontSize: 14, - color: Colors.black, - fontWeight: FontWeight.w500, - ), - ], - ), - const Divider( - color: Color(0xFFD6D6D6), - height: 20, - thickness: 1, - indent: 0, - endIndent: 0, - ), - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Texts( - TranslationBase.of(context).total, - fontSize: 14, - color: Colors.black, - fontWeight: FontWeight.bold, - ), - Texts( - "${TranslationBase.of(context).sar} ${(model.cartResponse.subtotal).toStringAsFixed(2)}", - fontSize: 14, - color: Colors.black, - fontWeight: FontWeight.bold, - ), - ], - ), - SizedBox( - height: 10, - ), - ], - ) + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Texts( + TranslationBase + .of(context) + .orderSummary, + fontSize: 14, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + SizedBox( + height: 20, + ), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Texts( + "${TranslationBase + .of(context) + .subtotal}", + fontSize: 14, + color: Colors.black, + fontWeight: FontWeight.w500, + ), + Texts( + "${TranslationBase + .of(context) + .sar} ${(model.cartResponse.subtotal) + .toStringAsFixed(2)}", + fontSize: 14, + color: Colors.black, + fontWeight: FontWeight.w500, + ), + ], + ), + const Divider( + color: Color(0xFFD6D6D6), + height: 20, + thickness: 1, + indent: 0, + endIndent: 0, + ), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Texts( + "${TranslationBase + .of(context) + .shipping}", + fontSize: 14, + color: Colors.black, + fontWeight: FontWeight.w500, + ), + Texts( + "${TranslationBase + .of(context) + .sar} ${(model + .totalAdditionalShippingCharge) + .toStringAsFixed(2)}", + fontSize: 14, + color: Colors.black, + fontWeight: FontWeight.w500, + ), + ], + ), + const Divider( + color: Color(0xFFD6D6D6), + height: 20, + thickness: 1, + indent: 0, + endIndent: 0, + ), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Texts( + "${TranslationBase + .of(context) + .vat}", + fontSize: 14, + color: Colors.black, + fontWeight: FontWeight.w500, + ), + Texts( + "${TranslationBase + .of(context) + .sar} ${(model.cartResponse + .subtotalVatAmount).toStringAsFixed( + 2)}", + fontSize: 14, + color: Colors.black, + fontWeight: FontWeight.w500, + ), + ], + ), + const Divider( + color: Color(0xFFD6D6D6), + height: 20, + thickness: 1, + indent: 0, + endIndent: 0, + ), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Texts( + TranslationBase + .of(context) + .total, + fontSize: 14, + color: Colors.black, + fontWeight: FontWeight.bold, + ), + Texts( + "${TranslationBase + .of(context) + .sar} ${(model.cartResponse.subtotal) + .toStringAsFixed(2)}", + fontSize: 14, + color: Colors.black, + fontWeight: FontWeight.bold, + ), + ], + ), + SizedBox( + height: 10, + ), + ], + ) : Container(), ) ], @@ -269,161 +303,172 @@ class _SelectAddressWidgetState extends State { @override Widget build(BuildContext context) { return Consumer( - builder: (ctx, paymentData, _) => Container( - color: Colors.white, - child: address == null - ? InkWell( - onTap: () => {_navigateToAddressPage()}, - child: Container( - margin: EdgeInsets.symmetric(vertical: 12, horizontal: 12), - child: Row( - children: [ - Image.asset( - "assets/images/pharmacy_module/ic_shipping_address.png", - width: 30.0, - height: 30.0, - fit: BoxFit.scaleDown, + builder: (ctx, paymentData, _) => + Container( + color: Colors.white, + child: address == null + ? InkWell( + onTap: () => {_navigateToAddressPage()}, + child: Container( + margin: EdgeInsets.symmetric(vertical: 12, horizontal: 12), + child: Row( + children: [ + Image.asset( + "assets/images/pharmacy_module/ic_shipping_address.png", + width: 30.0, + height: 30.0, + fit: BoxFit.scaleDown, + ), + Expanded( + child: Container( + padding: + EdgeInsets.symmetric(vertical: 0, horizontal: 6), + child: Texts( + TranslationBase + .of(context) + .selectAddress, + fontSize: 14, + fontWeight: FontWeight.bold, + color: Color(0xff0000ff), + ), ), - Expanded( - child: Container( - padding: - EdgeInsets.symmetric(vertical: 0, horizontal: 6), + ), + Icon( + Icons.arrow_forward_ios, + size: 20, + color: Colors.grey.shade400, + ), + ], + ), + ), + ) + : Container( + child: Container( + margin: EdgeInsets.symmetric(vertical: 12, horizontal: 12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Image.asset( + "assets/images/pharmacy_module/ic_shipping_mark.png", + width: 30.0, + height: 30.0, + fit: BoxFit.scaleDown, + ), + Expanded( + child: Container( + padding: EdgeInsets.symmetric( + vertical: 0, horizontal: 6), + child: Texts( + TranslationBase + .of(context) + .shippingAddress, + fontSize: 14, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ), + InkWell( + onTap: () => {_navigateToAddressPage()}, child: Texts( - TranslationBase.of(context).selectAddress, - fontSize: 14, - fontWeight: FontWeight.bold, + TranslationBase + .of(context) + .changeAddress, + fontSize: 12, + fontWeight: FontWeight.normal, color: Color(0xff0000ff), ), ), + ], + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Texts( + "${address.firstName} ${address.lastName}", + fontSize: 14, + fontWeight: FontWeight.bold, + color: Colors.black, ), - Icon( - Icons.arrow_forward_ios, - size: 20, - color: Colors.grey.shade400, + ), + Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: Texts( + "${address.address1} ${address.address2} ${address + .address2},, ${address.city}, ${address + .country} ${address.zipPostalCode}", + fontSize: 12, + fontWeight: FontWeight.normal, + color: Colors.grey.shade500, ), - ], - ), - ), - ) - : Container( - child: Container( - margin: EdgeInsets.symmetric(vertical: 12, horizontal: 12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Image.asset( - "assets/images/pharmacy_module/ic_shipping_mark.png", - width: 30.0, - height: 30.0, - fit: BoxFit.scaleDown, - ), - Expanded( - child: Container( - padding: EdgeInsets.symmetric( - vertical: 0, horizontal: 6), - child: Texts( - TranslationBase.of(context).shippingAddress, - fontSize: 14, - fontWeight: FontWeight.bold, - color: Colors.black, - ), - ), - ), - InkWell( - onTap: () => {_navigateToAddressPage()}, - child: Texts( - TranslationBase.of(context).changeAddress, - fontSize: 12, - fontWeight: FontWeight.normal, - color: Color(0xff0000ff), - ), + ), + Row( + children: [ + Container( + margin: const EdgeInsets.only(right: 8), + child: Icon( + Icons.phone, + size: 20, + color: Colors.black, ), - ], - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Texts( - "${address.firstName} ${address.lastName}", + ), + Texts( + "${address.phoneNumber}", fontSize: 14, fontWeight: FontWeight.bold, - color: Colors.black, + color: Colors.grey, ), - ), - Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: Texts( - "${address.address1} ${address.address2} ${address.address2},, ${address.city}, ${address.country} ${address.zipPostalCode}", - fontSize: 12, - fontWeight: FontWeight.normal, - color: Colors.grey.shade500, + ], + ), + Container( + margin: EdgeInsets.symmetric(vertical: 8), + child: SizedBox( + height: 2, + width: double.infinity, + child: Container( + color: Color(0xffefefef), ), ), - Row( - children: [ - Container( - margin: const EdgeInsets.only(right: 8), - child: Icon( - Icons.phone, - size: 20, - color: Colors.black, - ), - ), - Texts( - "${address.phoneNumber}", - fontSize: 14, + ), + Row( + children: [ + Image.asset( + "assets/images/pharmacy_module/ic_shipping_truck.png", + width: 30.0, + height: 30.0, + fit: BoxFit.scaleDown, + ), + Container( + padding: EdgeInsets.symmetric( + vertical: 0, horizontal: 6), + child: Texts( + "${TranslationBase + .of(context) + .shipBy}", + fontSize: 12, fontWeight: FontWeight.bold, - color: Colors.grey, - ), - ], - ), - Container( - margin: EdgeInsets.symmetric(vertical: 8), - child: SizedBox( - height: 2, - width: double.infinity, - child: Container( - color: Color(0xffefefef), + color: Colors.black, ), ), - ), - Row( - children: [ - Image.asset( - "assets/images/pharmacy_module/ic_shipping_truck.png", - width: 30.0, - height: 30.0, - fit: BoxFit.scaleDown, - ), - Container( - padding: EdgeInsets.symmetric( - vertical: 0, horizontal: 6), - child: Texts( - "${TranslationBase.of(context).shipBy}", - fontSize: 12, - fontWeight: FontWeight.bold, - color: Colors.black, - ), - ), - Container( - child: Image.asset( - paymentData.shippingOption - .shippingRateComputationMethodSystemName == - "Shipping.FixedOrByWeight" - ? "assets/images/pharmacy_module/payment/hmg_shipping_logo.png" - : "assets/images/pharmacy_module/payment/aramex_shipping_logo.png", - fit: BoxFit.contain, - ), - margin: EdgeInsets.symmetric(horizontal: 8), + Container( + child: Image.asset( + paymentData.shippingOption + .shippingRateComputationMethodSystemName == + "Shipping.FixedOrByWeight" + ? "assets/images/pharmacy_module/payment/hmg_shipping_logo.png" + : "assets/images/pharmacy_module/payment/aramex_shipping_logo.png", + fit: BoxFit.contain, ), - ], - ), - ], - ), + margin: EdgeInsets.symmetric(horizontal: 8), + ), + ], + ), + ], ), - ), // ic_shipping_mark.png - ), + ), + ), // ic_shipping_mark.png + ), ); } } @@ -443,16 +488,17 @@ class _SelectPaymentOptionWidgetState extends State { _navigateToPaymentOption() { Navigator.push(context, FadePage(page: PaymentMethodSelectPage())) - .then((result) => { - setState(() { - if (result != null) { - paymentOption = result; - widget.model.paymentCheckoutData.paymentOption = - paymentOption; - widget.model.paymentCheckoutData.updateData(); - } - }) - }); + .then((result) => + { + setState(() { + if (result != null) { + paymentOption = result; + widget.model.paymentCheckoutData.paymentOption = + paymentOption; + widget.model.paymentCheckoutData.updateData(); + } + }) + }); } @override @@ -469,85 +515,89 @@ class _SelectPaymentOptionWidgetState extends State { color: Colors.white, child: paymentOption == null ? InkWell( - onTap: () => {_navigateToPaymentOption()}, - child: Container( - margin: EdgeInsets.symmetric(vertical: 12, horizontal: 12), - child: Row( - children: [ - Image.asset( - "assets/images/pharmacy_module/ic_payment_option.png", - width: 30.0, - height: 30.0, - fit: BoxFit.scaleDown, - ), - Expanded( - child: Container( - padding: - EdgeInsets.symmetric(vertical: 0, horizontal: 6), - child: Texts( - TranslationBase.of(context).selectPaymentOption, - fontSize: 14, - fontWeight: FontWeight.bold, - color: Color(0xff0000ff), - ), - ), - ), - Icon( - Icons.arrow_forward_ios, - size: 20, - color: Colors.grey.shade400, - ), - ], + onTap: () => {_navigateToPaymentOption()}, + child: Container( + margin: EdgeInsets.symmetric(vertical: 12, horizontal: 12), + child: Row( + children: [ + Image.asset( + "assets/images/pharmacy_module/ic_payment_option.png", + width: 30.0, + height: 30.0, + fit: BoxFit.scaleDown, + ), + Expanded( + child: Container( + padding: + EdgeInsets.symmetric(vertical: 0, horizontal: 6), + child: Texts( + TranslationBase + .of(context) + .selectPaymentOption, + fontSize: 14, + fontWeight: FontWeight.bold, + color: Color(0xff0000ff), + ), ), ), - ) + Icon( + Icons.arrow_forward_ios, + size: 20, + color: Colors.grey.shade400, + ), + ], + ), + ), + ) : Container( - margin: EdgeInsets.symmetric(vertical: 12, horizontal: 12), - child: Row( - children: [ - Image.asset( - "assets/images/pharmacy_module/ic_payment_option.png", - width: 30.0, - height: 30.0, - fit: BoxFit.scaleDown, - ), - Container( - margin: EdgeInsets.symmetric(horizontal: 8), - padding: EdgeInsets.symmetric(horizontal: 4, vertical: 0), - decoration: new BoxDecoration( - color: Colors.grey.shade100, - shape: BoxShape.rectangle, - ), - child: Image.asset( - widget.model.getPaymentOptionImage(paymentOption), - width: 30.0, - height: 30.0, - fit: BoxFit.scaleDown, - ), - ), - Expanded( - child: Container( - padding: EdgeInsets.symmetric(vertical: 0, horizontal: 6), - child: Texts( - widget.model.getPaymentOptionName(paymentOption), - fontSize: 14, - fontWeight: FontWeight.bold, - color: Colors.black, - ), - ), - ), - InkWell( - onTap: () => {_navigateToPaymentOption()}, - child: Texts( - TranslationBase.of(context).changeMethod, - fontSize: 12, - fontWeight: FontWeight.normal, - color: Color(0xff0000ff), - ), - ), - ], + margin: EdgeInsets.symmetric(vertical: 12, horizontal: 12), + child: Row( + children: [ + Image.asset( + "assets/images/pharmacy_module/ic_payment_option.png", + width: 30.0, + height: 30.0, + fit: BoxFit.scaleDown, + ), + Container( + margin: EdgeInsets.symmetric(horizontal: 8), + padding: EdgeInsets.symmetric(horizontal: 4, vertical: 0), + decoration: new BoxDecoration( + color: Colors.grey.shade100, + shape: BoxShape.rectangle, + ), + child: Image.asset( + widget.model.getPaymentOptionImage(paymentOption), + width: 30.0, + height: 30.0, + fit: BoxFit.scaleDown, + ), + ), + Expanded( + child: Container( + padding: EdgeInsets.symmetric(vertical: 0, horizontal: 6), + child: Texts( + widget.model.getPaymentOptionName(paymentOption), + fontSize: 14, + fontWeight: FontWeight.bold, + color: Colors.black, + ), + ), + ), + InkWell( + onTap: () => {_navigateToPaymentOption()}, + child: Texts( + TranslationBase + .of(context) + .changeMethod, + fontSize: 12, + fontWeight: FontWeight.normal, + color: Color(0xff0000ff), ), ), + ], + ), + ), ); } } @@ -585,12 +635,15 @@ class _LakumWidgetState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Texts( - "${TranslationBase.of(context).lakumPoints}", + "${TranslationBase + .of(context) + .lakumPoints}", fontSize: 12, fontWeight: FontWeight.bold, ), Texts( - "${widget.model.paymentCheckoutData.lacumInformation.lakumInquiryInformationObjVersion.pointsBalanceAmount}", + "${widget.model.paymentCheckoutData.lacumInformation + .lakumInquiryInformationObjVersion.pointsBalanceAmount}", fontSize: 12, fontWeight: FontWeight.normal, ), @@ -605,7 +658,9 @@ class _LakumWidgetState extends State { mainAxisAlignment: MainAxisAlignment.end, children: [ Texts( - "${TranslationBase.of(context).riyal}", + "${TranslationBase + .of(context) + .riyal}", fontSize: 12, fontWeight: FontWeight.bold, ), @@ -619,19 +674,19 @@ class _LakumWidgetState extends State { decoration: InputDecoration( border: OutlineInputBorder( borderSide: - BorderSide(color: Colors.black, width: 0.2), + BorderSide(color: Colors.black, width: 0.2), gapPadding: 0, borderRadius: projectProvider.isArabic ? BorderRadius.only( - topRight: Radius.circular(8), - bottomRight: Radius.circular(8)) + topRight: Radius.circular(8), + bottomRight: Radius.circular(8)) : BorderRadius.only( - topLeft: Radius.circular(8), - bottomLeft: Radius.circular(8)), + topLeft: Radius.circular(8), + bottomLeft: Radius.circular(8)), ), disabledBorder: OutlineInputBorder( borderSide: - BorderSide(color: Colors.black, width: 0.4), + BorderSide(color: Colors.black, width: 0.4), gapPadding: 0, borderRadius: BorderRadius.only( topLeft: Radius.circular(8), @@ -643,22 +698,22 @@ class _LakumWidgetState extends State { style: TextStyle( fontSize: 14, color: widget - .model - .paymentCheckoutData - .lacumInformation - .lakumInquiryInformationObjVersion - .pointsBalanceAmount > - 0 + .model + .paymentCheckoutData + .lacumInformation + .lakumInquiryInformationObjVersion + .pointsBalanceAmount > + 0 ? Colors.black : Colors.grey, ), enabled: widget - .model - .paymentCheckoutData - .lacumInformation - .lakumInquiryInformationObjVersion - .pointsBalanceAmount == - 0 + .model + .paymentCheckoutData + .lacumInformation + .lakumInquiryInformationObjVersion + .pointsBalanceAmount == + 0 ? false : true, onChanged: (val) { @@ -677,7 +732,7 @@ class _LakumWidgetState extends State { widget.model.paymentCheckoutData.usedLakumPoints = 0; } _pointsController.text = - "${widget.model.paymentCheckoutData.usedLakumPoints}"; + "${widget.model.paymentCheckoutData.usedLakumPoints}"; }, ), ), @@ -689,18 +744,20 @@ class _LakumWidgetState extends State { shape: BoxShape.rectangle, borderRadius: projectProvider.isArabic ? BorderRadius.only( - topLeft: Radius.circular(6), - bottomLeft: Radius.circular(6)) + topLeft: Radius.circular(6), + bottomLeft: Radius.circular(6)) : BorderRadius.only( - topRight: Radius.circular(6), - bottomRight: Radius.circular(6)), + topRight: Radius.circular(6), + bottomRight: Radius.circular(6)), border: Border.fromBorderSide(BorderSide( color: Color(0xff3666E0), width: 0.8, )), ), child: Texts( - "${TranslationBase.of(context).use}", + "${TranslationBase + .of(context) + .use}", fontSize: 12, color: Colors.white, fontWeight: FontWeight.bold, @@ -719,106 +776,176 @@ class _LakumWidgetState extends State { class PaymentBottomWidget extends StatelessWidget { final OrderPreviewViewModel model; + BuildContext context; + MyInAppBrowser browser; + PaymentBottomWidget(this.model); @override Widget build(BuildContext context) { final scaffold = Scaffold.of(context); + this.context = context; return Container( margin: EdgeInsets.symmetric(horizontal: 10, vertical: 0), child: Consumer( - builder: (ctx, paymentData, _) => paymentData.cartDataVisible + builder: (ctx, paymentData, _) => + paymentData.cartDataVisible ? Container( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceEvenly, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Container( + margin: + EdgeInsets.symmetric(horizontal: 0, vertical: 4), + child: Row( children: [ - Container( - margin: - EdgeInsets.symmetric(horizontal: 0, vertical: 4), - child: Row( - children: [ - Texts( - "${TranslationBase.of(context).sar} ${(model.cartResponse.subtotal).toStringAsFixed(2)}", - fontSize: 14, - fontWeight: FontWeight.bold, - color: Color(0xff929295), - ), - Padding( - padding: - const EdgeInsets.symmetric(horizontal: 4), - child: Texts( - "${TranslationBase.of(context).inclusiveVat}", - fontSize: 8, - color: Color(0xff929295), - fontWeight: FontWeight.w600, - ), - ), - ], - ), - ), Texts( - "${model.cartResponse.quantityCount} ${TranslationBase.of(context).items}", - fontSize: 10, - color: Colors.grey, + "${TranslationBase + .of(context) + .sar} ${(model.cartResponse.subtotal) + .toStringAsFixed(2)}", + fontSize: 14, fontWeight: FontWeight.bold, + color: Color(0xff929295), ), - ], - ), - Container( - child: RaisedButton( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide( + Padding( + padding: + const EdgeInsets.symmetric(horizontal: 4), + child: Texts( + "${TranslationBase + .of(context) + .inclusiveVat}", + fontSize: 8, color: Color(0xff929295), - width: 1, + fontWeight: FontWeight.w600, ), ), - onPressed: (paymentData.address != null && - paymentData.paymentOption != null) - ? () async { - await model.makeOrder(); - if (model.state != ViewState.Idle) { - AppToast.showSuccessToast(message: "Order has been placed successfully!!"); - } else { - AppToast.showErrorToast(message: model.error); - } - Navigator.pop(context); - Navigator.pop(context); - } - : null, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 16), - child: new Text( - "${TranslationBase.of(context).proceedPay}", - style: new TextStyle( - color: (paymentData.address != null && - paymentData.paymentOption != null) - ? Colors.white - : Colors.grey.shade400, - fontWeight: FontWeight.bold, - fontSize: 12), - ), - ), - color: (paymentData.address != null && - paymentData.paymentOption != null) - ? Colors.green - : Color(0xff929295), - disabledColor: (paymentData.address != null && - paymentData.paymentOption != null) - ? Colors.green - : Color(0xff929295), - ), + ], ), - ], + ), + Texts( + "${model.cartResponse.quantityCount} ${TranslationBase + .of(context) + .items}", + fontSize: 10, + color: Colors.grey, + fontWeight: FontWeight.bold, + ), + ], + ), + Container( + child: RaisedButton( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide( + color: Color(0xff929295), + width: 1, + ), + ), + onPressed: (paymentData.address != null && + paymentData.paymentOption != null) + ? () async { + await model.makeOrder(); + if (model.state == ViewState.Idle) { + AppToast.showSuccessToast( + message: "Order has been placed successfully!!"); + openPayment(model.orderListModel[0], model.user); + } else { + AppToast.showErrorToast(message: model.error); + } + Navigator.pop(context); + Navigator.pop(context); + } + : null, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 16), + child: new Text( + "${TranslationBase + .of(context) + .proceedPay}", + style: new TextStyle( + color: (paymentData.address != null && + paymentData.paymentOption != null) + ? Colors.white + : Colors.grey.shade400, + fontWeight: FontWeight.bold, + fontSize: 12), + ), + ), + color: (paymentData.address != null && + paymentData.paymentOption != null) + ? Colors.green + : Color(0xff929295), + disabledColor: (paymentData.address != null && + paymentData.paymentOption != null) + ? Colors.green + : Color(0xff929295), ), - ) + ), + ], + ), + ) : Container(), ), ); } + + openPayment(OrderDetailModel order, + AuthenticatedUser authenticatedUser,) { + browser = new MyInAppBrowser( + onExitCallback: onBrowserExit, onLoadStartCallback: onBrowserLoadStart); + + browser.openPharmacyPaymentBrowser( + order, + order.orderTotal, + 'ePharmacy Order', + order.id, + order.billingAddress.email, + order.customValuesXml, + "${authenticatedUser.firstName} ${authenticatedUser + .middleName} ${authenticatedUser.lastName}", + authenticatedUser.patientID, + authenticatedUser, + browser); + } + + onBrowserLoadStart(String url) { + print("onBrowserLoadStart"); + print(url); + + MyInAppBrowser.successURLS.forEach((element) { + if (url.contains(element)) { + if (browser.isOpened()) browser.close(); + MyInAppBrowser.isPaymentDone = true; + return; + } + }); + + MyInAppBrowser.errorURLS.forEach((element) { + if (url.contains(element)) { + if (browser.isOpened()) browser.close(); + MyInAppBrowser.isPaymentDone = false; + return; + } + }); + } + + onBrowserExit(AppoitmentAllHistoryResultList appo, bool isPaymentMade) { + print("onBrowserExit Called!!!!"); + if (isPaymentMade) { + AppToast.showSuccessToast( + message: "شكراً\nPayment status for your order is Paid"); + Navigator.pop(context); + Navigator.pop(context); + } else { + AppToast.showErrorToast( + message: + "Transaction Failed!\Your transaction is field to some reason please try again or contact to the administration"); + } + } } diff --git a/lib/pages/pharmacies/widgets/ProductOrderItem.dart b/lib/pages/pharmacies/widgets/ProductOrderItem.dart index 92e2c39d..d7a82cc6 100644 --- a/lib/pages/pharmacies/widgets/ProductOrderItem.dart +++ b/lib/pages/pharmacies/widgets/ProductOrderItem.dart @@ -72,7 +72,7 @@ class _ProductOrderItemState extends State { child: Texts( projectProvider.isArabic ? widget.item.product.namen - : widget.item.product.name, + : "${widget.item.product.name}", regular: true, textAlign: TextAlign.justify, fontSize: 12, @@ -88,91 +88,90 @@ class _ProductOrderItemState extends State { ), margin: const EdgeInsets.only(bottom: 4), ), - Row( - children: [ - InkWell( - onTap: () => - {_quantityOnChangeClick(Operation.dec)}, - child: Container( - width: 25, - height: 25, - child: Center( - child: Texts( - "-", - color: Colors.grey.shade400, - )), - decoration: BoxDecoration( - border: Border.all( - color: Colors.grey.shade400, - width: 1.0, + Container( + margin: EdgeInsets.symmetric(vertical: 4), + child: Row( + children: [ + InkWell( + onTap: () => + {_quantityOnChangeClick(Operation.dec)}, + child: Container( + width: 25, + height: 25, + child: Icon( + Icons.remove, color: Colors.grey.shade400, size: 20, + ), + decoration: BoxDecoration( + border: Border.all( + color: Colors.grey.shade400, + width: 1.0, + ), ), ), ), - ), - Container( - margin: - const EdgeInsets.symmetric(horizontal: 4), - width: 25, - height: 25, - color: Colors.grey.shade300, - child: Center( - child: TextField( - cursorColor: Colors.black, - keyboardType: TextInputType.number, - controller: _quantityController, - textAlign: TextAlign.center, - onChanged: (text) { - setState(() { - var value = int.tryParse(text); - if (value == null) { - widget.item.quantity = 0; - } else { - widget.item.quantity = int.parse(text); - } - _totalPrice = - "${(widget.item.product.price * widget.item.quantity).toStringAsFixed(2)}"; - }); - }, - )), - ), - InkWell( - onTap: () => - {_quantityOnChangeClick(Operation.inc)}, - child: Container( + Container( + margin: + const EdgeInsets.symmetric(horizontal: 4), width: 25, height: 25, + color: Colors.grey.shade300, child: Center( - child: Texts( - "+", - color: Colors.grey.shade400, + child: TextField( + cursorColor: Colors.black, + keyboardType: TextInputType.number, + controller: _quantityController, + textAlign: TextAlign.center, + onChanged: (text) { + setState(() { + var value = int.tryParse(text); + if (value == null) { + widget.item.quantity = 0; + } else { + widget.item.quantity = int.parse(text); + } + _totalPrice = + "${(widget.item.product.price * widget.item.quantity).toStringAsFixed(2)}"; + }); + }, )), - decoration: BoxDecoration( - border: Border.all( - color: Colors.grey.shade400, - width: 1.0, - ), - ), ), - ), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Texts( - TranslationBase.of(context).total, - color: Colors.grey.shade500, - fontWeight: FontWeight.bold, - fontSize: 12, + InkWell( + onTap: () => + {_quantityOnChangeClick(Operation.inc)}, + child: Container( + width: 25, + height: 25, + child: Icon( + Icons.add, color: Colors.grey.shade400, size: 20, + ), + decoration: BoxDecoration( + border: Border.all( + color: Colors.grey.shade400, + width: 1.0, + ), ), - Texts( - "$_totalPrice ${projectProvider.isArabic ? widget.item.currencyn : widget.item.currency}", - fontSize: 12, - fontWeight: FontWeight.bold, - ) - ], + ), ), - ) - ], + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Texts( + TranslationBase.of(context).total, + color: Colors.grey.shade500, + fontWeight: FontWeight.bold, + fontSize: 12, + ), + Texts( + "$_totalPrice ${projectProvider.isArabic ? widget.item.currencyn : widget.item.currency}", + fontSize: 12, + fontWeight: FontWeight.bold, + ) + ], + ), + ) + ], + ), ) ], ), From f410ce20caf1f4c64caa679924de53548da43a0e Mon Sep 17 00:00:00 2001 From: Zohaib Iqbal Kambrani <> Date: Wed, 10 Mar 2021 18:00:53 +0300 Subject: [PATCH 06/26] Packages and Offers in Progress --- assets/images/discount_ar.png | Bin 0 -> 4615 bytes assets/images/discount_en.png | Bin 0 -> 5958 bytes assets/images/svg/discount_ar.svg | 37 + assets/images/svg/discount_en.svg | 43 + ios/Flutter/.last_build_id | 2 +- ios/Podfile.lock | 786 +++++++++++++++++- lib/config/config.dart | 4 +- lib/config/localized_values.dart | 1 + .../AddProductToCartRequestModel.dart | 26 + .../requests/CreateCustomerRequestModel.dart | 21 + .../OffersCategoriesRequestModel.dart | 8 +- .../requests/OffersProductsRequestModel.dart | 20 +- .../PackagesCartItemsResponseModel.dart | 132 +++ ...t => PackagesCategoriesResponseModel.dart} | 16 +- .../PackagesCustomerResponseModel.dart | 199 +++++ ...eModel.dart => PackagesResponseModel.dart} | 15 +- lib/core/service/client/base_app_client.dart | 107 ++- .../PackagesOffersServices.dart | 275 +++++- .../PackagesOffersViewModel.dart | 17 +- .../OfferCategoriesResponseModel_helper.dart | 8 +- .../OfferProductsResponseModel_helper.dart | 8 +- .../json/base/json_convert_content.dart | 36 +- lib/locator.dart | 9 +- lib/main.dart | 3 +- .../ClinicOfferAndPackagesPage.dart | 80 ++ .../OfferAndPackageDetailPage.dart | 228 +++++ .../OfferAndPackagesCartPage.dart | 376 +++++++++ .../packages_offers/OfferAndPackagesPage.dart | 416 +++++++++ lib/routes.dart | 9 +- lib/uitl/gif_loader_dialog_utils.dart | 6 +- lib/uitl/translations_delegate_base.dart | 5 + lib/uitl/utils.dart | 38 +- lib/widgets/CounterView.dart | 188 +++++ .../carousel_indicator.dart | 197 +++++ .../offers_packages/PackagesCartItemCard.dart | 217 +++++ .../offers_packages/PackagesOfferCard.dart | 157 ++++ .../offers_packages/offers_packages.dart | 1 - lib/widgets/others/StarRating.dart | 38 +- lib/widgets/others/app_scaffold_widget.dart | 44 +- pubspec.yaml | 7 +- 40 files changed, 3687 insertions(+), 93 deletions(-) create mode 100644 assets/images/discount_ar.png create mode 100644 assets/images/discount_en.png create mode 100644 assets/images/svg/discount_ar.svg create mode 100644 assets/images/svg/discount_en.svg create mode 100644 lib/core/model/packages_offers/requests/AddProductToCartRequestModel.dart create mode 100644 lib/core/model/packages_offers/requests/CreateCustomerRequestModel.dart create mode 100644 lib/core/model/packages_offers/responses/PackagesCartItemsResponseModel.dart rename lib/core/model/packages_offers/responses/{OfferCategoriesResponseModel.dart => PackagesCategoriesResponseModel.dart} (82%) create mode 100644 lib/core/model/packages_offers/responses/PackagesCustomerResponseModel.dart rename lib/core/model/packages_offers/responses/{OfferProductsResponseModel.dart => PackagesResponseModel.dart} (95%) create mode 100644 lib/pages/packages_offers/ClinicOfferAndPackagesPage.dart create mode 100644 lib/pages/packages_offers/OfferAndPackageDetailPage.dart create mode 100644 lib/pages/packages_offers/OfferAndPackagesCartPage.dart create mode 100644 lib/pages/packages_offers/OfferAndPackagesPage.dart create mode 100644 lib/widgets/CounterView.dart create mode 100644 lib/widgets/carousel_indicator/carousel_indicator.dart create mode 100644 lib/widgets/offers_packages/PackagesCartItemCard.dart create mode 100644 lib/widgets/offers_packages/PackagesOfferCard.dart diff --git a/assets/images/discount_ar.png b/assets/images/discount_ar.png new file mode 100644 index 0000000000000000000000000000000000000000..854d1c1f903e8e0d59bc54d20ec4dcaf2512208b GIT binary patch literal 4615 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 literal 0 HcmV?d00001 diff --git a/assets/images/svg/discount_ar.svg b/assets/images/svg/discount_ar.svg new file mode 100644 index 00000000..d9d6ec27 --- /dev/null +++ b/assets/images/svg/discount_ar.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + مصخ + + + + diff --git a/assets/images/svg/discount_en.svg b/assets/images/svg/discount_en.svg new file mode 100644 index 00000000..294cf19c --- /dev/null +++ b/assets/images/svg/discount_en.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Flutter/.last_build_id b/ios/Flutter/.last_build_id index b8024672..3b4ea73f 100644 --- a/ios/Flutter/.last_build_id +++ b/ios/Flutter/.last_build_id @@ -1 +1 @@ -59a6c452ee075b50114918f17f1ad8f5 \ No newline at end of file +45a7d43b55124e1b314759554f9a14d3 \ No newline at end of file diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 1df50aa4..0d6f024b 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,25 +1,809 @@ PODS: + - abseil/algorithm (0.20200225.0): + - abseil/algorithm/algorithm (= 0.20200225.0) + - abseil/algorithm/container (= 0.20200225.0) + - abseil/algorithm/algorithm (0.20200225.0): + - abseil/base/config + - abseil/algorithm/container (0.20200225.0): + - abseil/algorithm/algorithm + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/base (0.20200225.0): + - abseil/base/atomic_hook (= 0.20200225.0) + - abseil/base/base (= 0.20200225.0) + - abseil/base/base_internal (= 0.20200225.0) + - abseil/base/bits (= 0.20200225.0) + - abseil/base/config (= 0.20200225.0) + - abseil/base/core_headers (= 0.20200225.0) + - abseil/base/dynamic_annotations (= 0.20200225.0) + - abseil/base/endian (= 0.20200225.0) + - abseil/base/errno_saver (= 0.20200225.0) + - abseil/base/exponential_biased (= 0.20200225.0) + - abseil/base/log_severity (= 0.20200225.0) + - abseil/base/malloc_internal (= 0.20200225.0) + - abseil/base/periodic_sampler (= 0.20200225.0) + - abseil/base/pretty_function (= 0.20200225.0) + - abseil/base/raw_logging_internal (= 0.20200225.0) + - abseil/base/spinlock_wait (= 0.20200225.0) + - abseil/base/throw_delegate (= 0.20200225.0) + - abseil/base/atomic_hook (0.20200225.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/base (0.20200225.0): + - abseil/base/atomic_hook + - abseil/base/base_internal + - abseil/base/config + - abseil/base/core_headers + - abseil/base/dynamic_annotations + - abseil/base/log_severity + - abseil/base/raw_logging_internal + - abseil/base/spinlock_wait + - abseil/meta/type_traits + - abseil/base/base_internal (0.20200225.0): + - abseil/base/config + - abseil/meta/type_traits + - abseil/base/bits (0.20200225.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/config (0.20200225.0) + - abseil/base/core_headers (0.20200225.0): + - abseil/base/config + - abseil/base/dynamic_annotations (0.20200225.0) + - abseil/base/endian (0.20200225.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/errno_saver (0.20200225.0): + - abseil/base/config + - abseil/base/exponential_biased (0.20200225.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/log_severity (0.20200225.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/malloc_internal (0.20200225.0): + - abseil/base/base + - abseil/base/base_internal + - abseil/base/config + - abseil/base/core_headers + - abseil/base/dynamic_annotations + - abseil/base/raw_logging_internal + - abseil/base/periodic_sampler (0.20200225.0): + - abseil/base/core_headers + - abseil/base/exponential_biased + - abseil/base/pretty_function (0.20200225.0) + - abseil/base/raw_logging_internal (0.20200225.0): + - abseil/base/atomic_hook + - abseil/base/config + - abseil/base/core_headers + - abseil/base/log_severity + - abseil/base/spinlock_wait (0.20200225.0): + - abseil/base/base_internal + - abseil/base/core_headers + - abseil/base/errno_saver + - abseil/base/throw_delegate (0.20200225.0): + - abseil/base/config + - abseil/base/raw_logging_internal + - abseil/container/compressed_tuple (0.20200225.0): + - abseil/utility/utility + - abseil/container/inlined_vector (0.20200225.0): + - abseil/algorithm/algorithm + - abseil/base/core_headers + - abseil/base/throw_delegate + - abseil/container/inlined_vector_internal + - abseil/memory/memory + - abseil/container/inlined_vector_internal (0.20200225.0): + - abseil/base/core_headers + - abseil/container/compressed_tuple + - abseil/memory/memory + - abseil/meta/type_traits + - abseil/types/span + - abseil/memory (0.20200225.0): + - abseil/memory/memory (= 0.20200225.0) + - abseil/memory/memory (0.20200225.0): + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/meta (0.20200225.0): + - abseil/meta/type_traits (= 0.20200225.0) + - abseil/meta/type_traits (0.20200225.0): + - abseil/base/config + - abseil/numeric/int128 (0.20200225.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/strings/internal (0.20200225.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/base/endian + - abseil/base/raw_logging_internal + - abseil/meta/type_traits + - abseil/strings/str_format (0.20200225.0): + - abseil/strings/str_format_internal + - abseil/strings/str_format_internal (0.20200225.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/numeric/int128 + - abseil/strings/strings + - abseil/types/span + - abseil/strings/strings (0.20200225.0): + - abseil/base/base + - abseil/base/bits + - abseil/base/config + - abseil/base/core_headers + - abseil/base/endian + - abseil/base/raw_logging_internal + - abseil/base/throw_delegate + - abseil/memory/memory + - abseil/meta/type_traits + - abseil/numeric/int128 + - abseil/strings/internal + - abseil/time (0.20200225.0): + - abseil/time/internal (= 0.20200225.0) + - abseil/time/time (= 0.20200225.0) + - abseil/time/internal (0.20200225.0): + - abseil/time/internal/cctz (= 0.20200225.0) + - abseil/time/internal/cctz (0.20200225.0): + - abseil/time/internal/cctz/civil_time (= 0.20200225.0) + - abseil/time/internal/cctz/time_zone (= 0.20200225.0) + - abseil/time/internal/cctz/civil_time (0.20200225.0): + - abseil/base/config + - abseil/time/internal/cctz/time_zone (0.20200225.0): + - abseil/base/config + - abseil/time/internal/cctz/civil_time + - abseil/time/time (0.20200225.0): + - abseil/base/base + - abseil/base/core_headers + - abseil/base/raw_logging_internal + - abseil/numeric/int128 + - abseil/strings/strings + - abseil/time/internal/cctz/civil_time + - abseil/time/internal/cctz/time_zone + - abseil/types (0.20200225.0): + - abseil/types/any (= 0.20200225.0) + - abseil/types/bad_any_cast (= 0.20200225.0) + - abseil/types/bad_any_cast_impl (= 0.20200225.0) + - abseil/types/bad_optional_access (= 0.20200225.0) + - abseil/types/bad_variant_access (= 0.20200225.0) + - abseil/types/compare (= 0.20200225.0) + - abseil/types/optional (= 0.20200225.0) + - abseil/types/span (= 0.20200225.0) + - abseil/types/variant (= 0.20200225.0) + - abseil/types/any (0.20200225.0): + - abseil/base/config + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/types/bad_any_cast + - abseil/utility/utility + - abseil/types/bad_any_cast (0.20200225.0): + - abseil/base/config + - abseil/types/bad_any_cast_impl + - abseil/types/bad_any_cast_impl (0.20200225.0): + - abseil/base/config + - abseil/base/raw_logging_internal + - abseil/types/bad_optional_access (0.20200225.0): + - abseil/base/config + - abseil/base/raw_logging_internal + - abseil/types/bad_variant_access (0.20200225.0): + - abseil/base/config + - abseil/base/raw_logging_internal + - abseil/types/compare (0.20200225.0): + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/types/optional (0.20200225.0): + - abseil/base/base_internal + - abseil/base/config + - abseil/base/core_headers + - abseil/memory/memory + - abseil/meta/type_traits + - abseil/types/bad_optional_access + - abseil/utility/utility + - abseil/types/span (0.20200225.0): + - abseil/algorithm/algorithm + - abseil/base/core_headers + - abseil/base/throw_delegate + - abseil/meta/type_traits + - abseil/types/variant (0.20200225.0): + - abseil/base/base_internal + - abseil/base/config + - abseil/base/core_headers + - abseil/meta/type_traits + - abseil/types/bad_variant_access + - abseil/utility/utility + - abseil/utility/utility (0.20200225.0): + - abseil/base/base_internal + - abseil/base/config + - abseil/meta/type_traits + - android_intent (0.0.1): + - Flutter + - barcode_scan_fix (0.0.1): + - Flutter + - MTBBarcodeScanner + - BoringSSL-GRPC (0.0.7): + - BoringSSL-GRPC/Implementation (= 0.0.7) + - BoringSSL-GRPC/Interface (= 0.0.7) + - BoringSSL-GRPC/Implementation (0.0.7): + - BoringSSL-GRPC/Interface (= 0.0.7) + - BoringSSL-GRPC/Interface (0.0.7) + - cloud_firestore (0.14.4): + - Firebase/CoreOnly (~> 6.33.0) + - Firebase/Firestore (~> 6.33.0) + - firebase_core + - Flutter + - cloud_firestore_web (0.1.0): + - Flutter + - connectivity (0.0.1): + - Flutter + - Reachability + - connectivity_for_web (0.1.0): + - Flutter + - connectivity_macos (0.0.1): + - Flutter + - device_calendar (0.0.1): + - Flutter + - device_info (0.0.1): + - Flutter + - DKImagePickerController/Core (4.3.2): + - DKImagePickerController/ImageDataManager + - DKImagePickerController/Resource + - DKImagePickerController/ImageDataManager (4.3.2) + - DKImagePickerController/PhotoGallery (4.3.2): + - DKImagePickerController/Core + - DKPhotoGallery + - DKImagePickerController/Resource (4.3.2) + - DKPhotoGallery (0.0.17): + - DKPhotoGallery/Core (= 0.0.17) + - DKPhotoGallery/Model (= 0.0.17) + - DKPhotoGallery/Preview (= 0.0.17) + - DKPhotoGallery/Resource (= 0.0.17) + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Core (0.0.17): + - DKPhotoGallery/Model + - DKPhotoGallery/Preview + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Model (0.0.17): + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Preview (0.0.17): + - DKPhotoGallery/Model + - DKPhotoGallery/Resource + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Resource (0.0.17): + - SDWebImage + - SwiftyGif + - file_picker (0.0.1): + - DKImagePickerController/PhotoGallery + - Flutter + - file_picker_web (0.0.1): + - Flutter + - Firebase/CoreOnly (6.33.0): + - FirebaseCore (= 6.10.3) + - Firebase/Firestore (6.33.0): + - Firebase/CoreOnly + - FirebaseFirestore (~> 1.18.0) + - Firebase/Messaging (6.33.0): + - Firebase/CoreOnly + - FirebaseMessaging (~> 4.7.0) + - firebase_core (0.5.3): + - Firebase/CoreOnly (~> 6.33.0) + - Flutter + - firebase_core_web (0.1.0): + - Flutter + - firebase_messaging (7.0.3): + - Firebase/CoreOnly (~> 6.33.0) + - Firebase/Messaging (~> 6.33.0) + - firebase_core + - Flutter + - FirebaseCore (6.10.3): + - FirebaseCoreDiagnostics (~> 1.6) + - GoogleUtilities/Environment (~> 6.7) + - GoogleUtilities/Logger (~> 6.7) + - FirebaseCoreDiagnostics (1.7.0): + - GoogleDataTransport (~> 7.4) + - GoogleUtilities/Environment (~> 6.7) + - GoogleUtilities/Logger (~> 6.7) + - nanopb (~> 1.30906.0) + - FirebaseFirestore (1.18.0): + - abseil/algorithm (= 0.20200225.0) + - abseil/base (= 0.20200225.0) + - abseil/memory (= 0.20200225.0) + - abseil/meta (= 0.20200225.0) + - abseil/strings/strings (= 0.20200225.0) + - abseil/time (= 0.20200225.0) + - abseil/types (= 0.20200225.0) + - FirebaseCore (~> 6.10) + - "gRPC-C++ (~> 1.28.0)" + - leveldb-library (~> 1.22) + - nanopb (~> 1.30906.0) + - FirebaseInstallations (1.7.0): + - FirebaseCore (~> 6.10) + - GoogleUtilities/Environment (~> 6.7) + - GoogleUtilities/UserDefaults (~> 6.7) + - PromisesObjC (~> 1.2) + - FirebaseInstanceID (4.8.0): + - FirebaseCore (~> 6.10) + - FirebaseInstallations (~> 1.6) + - GoogleUtilities/Environment (~> 6.7) + - GoogleUtilities/UserDefaults (~> 6.7) + - FirebaseMessaging (4.7.1): + - FirebaseCore (~> 6.10) + - FirebaseInstanceID (~> 4.7) + - GoogleUtilities/AppDelegateSwizzler (~> 6.7) + - GoogleUtilities/Environment (~> 6.7) + - GoogleUtilities/Reachability (~> 6.7) + - GoogleUtilities/UserDefaults (~> 6.7) + - Protobuf (>= 3.9.2, ~> 3.9) - Flutter (1.0.0) + - flutter_email_sender (0.0.1): + - Flutter + - flutter_flexible_toast (0.0.1): + - Flutter + - flutter_inappwebview (0.0.1): + - Flutter + - flutter_local_notifications (0.0.1): + - Flutter + - flutter_plugin_android_lifecycle (0.0.1): + - Flutter + - flutter_tts (0.0.1): + - Flutter + - FMDB (2.7.5): + - FMDB/standard (= 2.7.5) + - FMDB/standard (2.7.5) + - geolocator (6.2.0): + - Flutter + - google_maps_flutter (0.0.1): + - Flutter + - GoogleMaps (< 3.10) + - GoogleDataTransport (7.5.1): + - nanopb (~> 1.30906.0) + - GoogleMaps (3.9.0): + - GoogleMaps/Maps (= 3.9.0) + - GoogleMaps/Base (3.9.0) + - GoogleMaps/Maps (3.9.0): + - GoogleMaps/Base + - GoogleUtilities/AppDelegateSwizzler (6.7.2): + - GoogleUtilities/Environment + - GoogleUtilities/Logger + - GoogleUtilities/Network + - GoogleUtilities/Environment (6.7.2): + - PromisesObjC (~> 1.2) + - GoogleUtilities/Logger (6.7.2): + - GoogleUtilities/Environment + - GoogleUtilities/Network (6.7.2): + - GoogleUtilities/Logger + - "GoogleUtilities/NSData+zlib" + - GoogleUtilities/Reachability + - "GoogleUtilities/NSData+zlib (6.7.2)" + - GoogleUtilities/Reachability (6.7.2): + - GoogleUtilities/Logger + - GoogleUtilities/UserDefaults (6.7.2): + - GoogleUtilities/Logger + - "gRPC-C++ (1.28.2)": + - "gRPC-C++/Implementation (= 1.28.2)" + - "gRPC-C++/Interface (= 1.28.2)" + - "gRPC-C++/Implementation (1.28.2)": + - abseil/container/inlined_vector (= 0.20200225.0) + - abseil/memory/memory (= 0.20200225.0) + - abseil/strings/str_format (= 0.20200225.0) + - abseil/strings/strings (= 0.20200225.0) + - abseil/types/optional (= 0.20200225.0) + - "gRPC-C++/Interface (= 1.28.2)" + - gRPC-Core (= 1.28.2) + - "gRPC-C++/Interface (1.28.2)" + - gRPC-Core (1.28.2): + - gRPC-Core/Implementation (= 1.28.2) + - gRPC-Core/Interface (= 1.28.2) + - gRPC-Core/Implementation (1.28.2): + - abseil/container/inlined_vector (= 0.20200225.0) + - abseil/memory/memory (= 0.20200225.0) + - abseil/strings/str_format (= 0.20200225.0) + - abseil/strings/strings (= 0.20200225.0) + - abseil/types/optional (= 0.20200225.0) + - BoringSSL-GRPC (= 0.0.7) + - gRPC-Core/Interface (= 1.28.2) + - gRPC-Core/Interface (1.28.2) + - hexcolor (0.0.1): + - Flutter + - image_cropper (0.0.3): + - Flutter + - TOCropViewController (~> 2.5.4) + - image_picker (0.0.1): + - Flutter + - just_audio (0.0.1): + - Flutter + - leveldb-library (1.22) + - local_auth (0.0.1): + - Flutter + - location (0.0.1): + - Flutter + - manage_calendar_events (0.0.1): + - Flutter + - map_launcher (0.0.1): + - Flutter + - maps_launcher (0.0.1): + - Flutter + - MTBBarcodeScanner (5.0.11) + - nanopb (1.30906.0): + - nanopb/decode (= 1.30906.0) + - nanopb/encode (= 1.30906.0) + - nanopb/decode (1.30906.0) + - nanopb/encode (1.30906.0) + - native_device_orientation (0.0.1): + - Flutter - NVActivityIndicatorView (5.1.1): - NVActivityIndicatorView/Base (= 5.1.1) - NVActivityIndicatorView/Base (5.1.1) + - path_provider (0.0.1): + - Flutter + - path_provider_linux (0.0.1): + - Flutter + - path_provider_macos (0.0.1): + - Flutter + - path_provider_windows (0.0.1): + - Flutter + - "permission_handler (5.1.0+2)": + - Flutter + - PromisesObjC (1.2.12) + - Protobuf (3.14.0) + - Reachability (3.2) + - screen (0.0.1): + - Flutter + - SDWebImage (5.10.4): + - SDWebImage/Core (= 5.10.4) + - SDWebImage/Core (5.10.4) + - shared_preferences (0.0.1): + - Flutter + - shared_preferences_linux (0.0.1): + - Flutter + - shared_preferences_macos (0.0.1): + - Flutter + - shared_preferences_web (0.0.1): + - Flutter + - shared_preferences_windows (0.0.1): + - Flutter + - speech_to_text (0.0.1): + - Flutter + - Try + - sqflite (0.0.2): + - Flutter + - FMDB (>= 2.7.5) + - SwiftyGif (5.4.0) + - TOCropViewController (2.5.5) + - Try (2.1.1) + - "twilio_programmable_video (0.5.0+4)": + - Flutter + - TwilioVideo (~> 3.4) + - TwilioVideo (3.8.0) + - url_launcher (0.0.1): + - Flutter + - url_launcher_linux (0.0.1): + - Flutter + - url_launcher_macos (0.0.1): + - Flutter + - url_launcher_web (0.0.1): + - Flutter + - url_launcher_windows (0.0.1): + - Flutter + - vibration (1.7.3): + - Flutter + - vibration_web (1.6.2): + - Flutter + - video_player (0.0.1): + - Flutter + - video_player_web (0.0.1): + - Flutter + - wakelock (0.0.1): + - Flutter + - webview_flutter (0.0.1): + - Flutter + - wifi (0.0.1): + - Flutter DEPENDENCIES: + - android_intent (from `.symlinks/plugins/android_intent/ios`) + - barcode_scan_fix (from `.symlinks/plugins/barcode_scan_fix/ios`) + - cloud_firestore (from `.symlinks/plugins/cloud_firestore/ios`) + - cloud_firestore_web (from `.symlinks/plugins/cloud_firestore_web/ios`) + - connectivity (from `.symlinks/plugins/connectivity/ios`) + - connectivity_for_web (from `.symlinks/plugins/connectivity_for_web/ios`) + - connectivity_macos (from `.symlinks/plugins/connectivity_macos/ios`) + - device_calendar (from `.symlinks/plugins/device_calendar/ios`) + - device_info (from `.symlinks/plugins/device_info/ios`) + - file_picker (from `.symlinks/plugins/file_picker/ios`) + - file_picker_web (from `.symlinks/plugins/file_picker_web/ios`) + - firebase_core (from `.symlinks/plugins/firebase_core/ios`) + - firebase_core_web (from `.symlinks/plugins/firebase_core_web/ios`) + - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) - Flutter (from `Flutter`) + - flutter_email_sender (from `.symlinks/plugins/flutter_email_sender/ios`) + - flutter_flexible_toast (from `.symlinks/plugins/flutter_flexible_toast/ios`) + - flutter_inappwebview (from `.symlinks/plugins/flutter_inappwebview/ios`) + - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) + - flutter_plugin_android_lifecycle (from `.symlinks/plugins/flutter_plugin_android_lifecycle/ios`) + - flutter_tts (from `.symlinks/plugins/flutter_tts/ios`) + - geolocator (from `.symlinks/plugins/geolocator/ios`) + - google_maps_flutter (from `.symlinks/plugins/google_maps_flutter/ios`) + - hexcolor (from `.symlinks/plugins/hexcolor/ios`) + - image_cropper (from `.symlinks/plugins/image_cropper/ios`) + - image_picker (from `.symlinks/plugins/image_picker/ios`) + - just_audio (from `.symlinks/plugins/just_audio/ios`) + - local_auth (from `.symlinks/plugins/local_auth/ios`) + - location (from `.symlinks/plugins/location/ios`) + - manage_calendar_events (from `.symlinks/plugins/manage_calendar_events/ios`) + - map_launcher (from `.symlinks/plugins/map_launcher/ios`) + - maps_launcher (from `.symlinks/plugins/maps_launcher/ios`) + - native_device_orientation (from `.symlinks/plugins/native_device_orientation/ios`) - NVActivityIndicatorView + - path_provider (from `.symlinks/plugins/path_provider/ios`) + - path_provider_linux (from `.symlinks/plugins/path_provider_linux/ios`) + - path_provider_macos (from `.symlinks/plugins/path_provider_macos/ios`) + - path_provider_windows (from `.symlinks/plugins/path_provider_windows/ios`) + - permission_handler (from `.symlinks/plugins/permission_handler/ios`) + - screen (from `.symlinks/plugins/screen/ios`) + - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) + - shared_preferences_linux (from `.symlinks/plugins/shared_preferences_linux/ios`) + - shared_preferences_macos (from `.symlinks/plugins/shared_preferences_macos/ios`) + - shared_preferences_web (from `.symlinks/plugins/shared_preferences_web/ios`) + - shared_preferences_windows (from `.symlinks/plugins/shared_preferences_windows/ios`) + - speech_to_text (from `.symlinks/plugins/speech_to_text/ios`) + - sqflite (from `.symlinks/plugins/sqflite/ios`) + - twilio_programmable_video (from `.symlinks/plugins/twilio_programmable_video/ios`) + - url_launcher (from `.symlinks/plugins/url_launcher/ios`) + - url_launcher_linux (from `.symlinks/plugins/url_launcher_linux/ios`) + - url_launcher_macos (from `.symlinks/plugins/url_launcher_macos/ios`) + - url_launcher_web (from `.symlinks/plugins/url_launcher_web/ios`) + - url_launcher_windows (from `.symlinks/plugins/url_launcher_windows/ios`) + - vibration (from `.symlinks/plugins/vibration/ios`) + - vibration_web (from `.symlinks/plugins/vibration_web/ios`) + - video_player (from `.symlinks/plugins/video_player/ios`) + - video_player_web (from `.symlinks/plugins/video_player_web/ios`) + - wakelock (from `.symlinks/plugins/wakelock/ios`) + - webview_flutter (from `.symlinks/plugins/webview_flutter/ios`) + - wifi (from `.symlinks/plugins/wifi/ios`) SPEC REPOS: trunk: + - abseil + - BoringSSL-GRPC + - DKImagePickerController + - DKPhotoGallery + - Firebase + - FirebaseCore + - FirebaseCoreDiagnostics + - FirebaseFirestore + - FirebaseInstallations + - FirebaseInstanceID + - FirebaseMessaging + - FMDB + - GoogleDataTransport + - GoogleMaps + - GoogleUtilities + - "gRPC-C++" + - gRPC-Core + - leveldb-library + - MTBBarcodeScanner + - nanopb - NVActivityIndicatorView + - PromisesObjC + - Protobuf + - Reachability + - SDWebImage + - SwiftyGif + - TOCropViewController + - Try + - TwilioVideo EXTERNAL SOURCES: + android_intent: + :path: ".symlinks/plugins/android_intent/ios" + barcode_scan_fix: + :path: ".symlinks/plugins/barcode_scan_fix/ios" + cloud_firestore: + :path: ".symlinks/plugins/cloud_firestore/ios" + cloud_firestore_web: + :path: ".symlinks/plugins/cloud_firestore_web/ios" + connectivity: + :path: ".symlinks/plugins/connectivity/ios" + connectivity_for_web: + :path: ".symlinks/plugins/connectivity_for_web/ios" + connectivity_macos: + :path: ".symlinks/plugins/connectivity_macos/ios" + device_calendar: + :path: ".symlinks/plugins/device_calendar/ios" + device_info: + :path: ".symlinks/plugins/device_info/ios" + file_picker: + :path: ".symlinks/plugins/file_picker/ios" + file_picker_web: + :path: ".symlinks/plugins/file_picker_web/ios" + firebase_core: + :path: ".symlinks/plugins/firebase_core/ios" + firebase_core_web: + :path: ".symlinks/plugins/firebase_core_web/ios" + firebase_messaging: + :path: ".symlinks/plugins/firebase_messaging/ios" Flutter: :path: Flutter + flutter_email_sender: + :path: ".symlinks/plugins/flutter_email_sender/ios" + flutter_flexible_toast: + :path: ".symlinks/plugins/flutter_flexible_toast/ios" + flutter_inappwebview: + :path: ".symlinks/plugins/flutter_inappwebview/ios" + flutter_local_notifications: + :path: ".symlinks/plugins/flutter_local_notifications/ios" + flutter_plugin_android_lifecycle: + :path: ".symlinks/plugins/flutter_plugin_android_lifecycle/ios" + flutter_tts: + :path: ".symlinks/plugins/flutter_tts/ios" + geolocator: + :path: ".symlinks/plugins/geolocator/ios" + google_maps_flutter: + :path: ".symlinks/plugins/google_maps_flutter/ios" + hexcolor: + :path: ".symlinks/plugins/hexcolor/ios" + image_cropper: + :path: ".symlinks/plugins/image_cropper/ios" + image_picker: + :path: ".symlinks/plugins/image_picker/ios" + just_audio: + :path: ".symlinks/plugins/just_audio/ios" + local_auth: + :path: ".symlinks/plugins/local_auth/ios" + location: + :path: ".symlinks/plugins/location/ios" + manage_calendar_events: + :path: ".symlinks/plugins/manage_calendar_events/ios" + map_launcher: + :path: ".symlinks/plugins/map_launcher/ios" + maps_launcher: + :path: ".symlinks/plugins/maps_launcher/ios" + native_device_orientation: + :path: ".symlinks/plugins/native_device_orientation/ios" + path_provider: + :path: ".symlinks/plugins/path_provider/ios" + path_provider_linux: + :path: ".symlinks/plugins/path_provider_linux/ios" + path_provider_macos: + :path: ".symlinks/plugins/path_provider_macos/ios" + path_provider_windows: + :path: ".symlinks/plugins/path_provider_windows/ios" + permission_handler: + :path: ".symlinks/plugins/permission_handler/ios" + screen: + :path: ".symlinks/plugins/screen/ios" + shared_preferences: + :path: ".symlinks/plugins/shared_preferences/ios" + shared_preferences_linux: + :path: ".symlinks/plugins/shared_preferences_linux/ios" + shared_preferences_macos: + :path: ".symlinks/plugins/shared_preferences_macos/ios" + shared_preferences_web: + :path: ".symlinks/plugins/shared_preferences_web/ios" + shared_preferences_windows: + :path: ".symlinks/plugins/shared_preferences_windows/ios" + speech_to_text: + :path: ".symlinks/plugins/speech_to_text/ios" + sqflite: + :path: ".symlinks/plugins/sqflite/ios" + twilio_programmable_video: + :path: ".symlinks/plugins/twilio_programmable_video/ios" + url_launcher: + :path: ".symlinks/plugins/url_launcher/ios" + url_launcher_linux: + :path: ".symlinks/plugins/url_launcher_linux/ios" + url_launcher_macos: + :path: ".symlinks/plugins/url_launcher_macos/ios" + url_launcher_web: + :path: ".symlinks/plugins/url_launcher_web/ios" + url_launcher_windows: + :path: ".symlinks/plugins/url_launcher_windows/ios" + vibration: + :path: ".symlinks/plugins/vibration/ios" + vibration_web: + :path: ".symlinks/plugins/vibration_web/ios" + video_player: + :path: ".symlinks/plugins/video_player/ios" + video_player_web: + :path: ".symlinks/plugins/video_player_web/ios" + wakelock: + :path: ".symlinks/plugins/wakelock/ios" + webview_flutter: + :path: ".symlinks/plugins/webview_flutter/ios" + wifi: + :path: ".symlinks/plugins/wifi/ios" SPEC CHECKSUMS: + abseil: 6c8eb7892aefa08d929b39f9bb108e5367e3228f + android_intent: 367df2f1277a74e4a90e14a8ab3df3112d087052 + barcode_scan_fix: 80dd65de55f27eec6591dd077c8b85f2b79e31f1 + BoringSSL-GRPC: 8edf627ee524575e2f8d19d56f068b448eea3879 + cloud_firestore: b8c0e15fa49dfff87c2817d288b577e5dca2df13 + cloud_firestore_web: 9ec3dc7f5f98de5129339802d491c1204462bfec + connectivity: c4130b2985d4ef6fd26f9702e886bd5260681467 + connectivity_for_web: 2b8584556930d4bd490d82b836bcf45067ce345b + connectivity_macos: e2e9731b6b22dda39eb1b128f6969d574460e191 + device_calendar: 23b28a5f1ab3bf77e34542fb1167e1b8b29a98f5 + device_info: d7d233b645a32c40dfdc212de5cf646ca482f175 + DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d + DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 + file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 + file_picker_web: 37b10786e88885124fac99dc899866e78a132ef3 + Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5 + firebase_core: 5d6a02f3d85acd5f8321c2d6d62877626a670659 + firebase_core_web: d501d8b946b60c8af265428ce483b0fff5ad52d1 + firebase_messaging: 0aea2cd5885b65e19ede58ee3507f485c992cc75 + FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd + FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1 + FirebaseFirestore: adff4877869ca91a11250cc0989a6cd56bad163f + FirebaseInstallations: 466c7b4d1f58fe16707693091da253726a731ed2 + FirebaseInstanceID: bd3ffc24367f901a43c063b36c640b345a4a5dd1 + FirebaseMessaging: 5eca4ef173de76253352511aafef774caa1cba2a Flutter: 0e3d915762c693b495b44d77113d4970485de6ec + flutter_email_sender: f787522d0e82f50e5766c1213dbffff22fdcf009 + flutter_flexible_toast: 0547e740cae0c33bb7c51bcd931233f4584e1143 + flutter_inappwebview: 69dfbac46157b336ffbec19ca6dfd4638c7bf189 + flutter_local_notifications: 9e4738ce2471c5af910d961a6b7eadcf57c50186 + flutter_plugin_android_lifecycle: dc0b544e129eebb77a6bfb1239d4d1c673a60a35 + flutter_tts: 0f492aab6accf87059b72354fcb4ba934304771d + FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a + geolocator: f5e3de65e241caba7ce3e8a618803387bda73384 + google_maps_flutter: c7f9c73576de1fbe152a227bfd6e6c4ae8088619 + GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833 + GoogleMaps: 4b5346bddfe6911bb89155d43c903020170523ac + GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3 + "gRPC-C++": 13d8ccef97d5c3c441b7e3c529ef28ebee86fad2 + gRPC-Core: 4afa11bfbedf7cdecd04de535a9e046893404ed5 + hexcolor: fdfb9c4258ad96e949c2dbcdf790a62194b8aa89 + image_cropper: c8f9b4157933c7bb965a66d1c5e6c8fd408c6eb4 + image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09 + just_audio: baa7252489dbcf47a4c7cc9ca663e9661c99aafa + leveldb-library: 55d93ee664b4007aac644a782d11da33fba316f7 + local_auth: 25938960984c3a7f6e3253e3f8d962fdd16852bd + location: 3a2eed4dd2fab25e7b7baf2a9efefe82b512d740 + manage_calendar_events: 0338d505ea26cdfd20cd883279bc28afa11eca34 + map_launcher: e325db1261d029ff33e08e03baccffe09593ffea + maps_launcher: eae38ee13a9c3f210fa04e04bb4c073fa4c6ed92 + MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb + nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc + native_device_orientation: e24d00be281de72996640885d80e706142707660 NVActivityIndicatorView: 1f6c5687f1171810aa27a3296814dc2d7dec3667 + path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c + path_provider_linux: 4d630dc393e1f20364f3e3b4a2ff41d9674a84e4 + path_provider_macos: f760a3c5b04357c380e2fddb6f9db6f3015897e0 + path_provider_windows: a2b81600c677ac1959367280991971cb9a1edb3b + permission_handler: ccb20a9fad0ee9b1314a52b70b76b473c5f8dab0 + PromisesObjC: 3113f7f76903778cf4a0586bd1ab89329a0b7b97 + Protobuf: 0cde852566359049847168e51bd1c690e0f70056 + Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 + screen: abd91ca7bf3426e1cc3646d27e9b2358d6bf07b0 + SDWebImage: c666b97e1fa9c64b4909816a903322018f0a9c84 + shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d + shared_preferences_linux: afefbfe8d921e207f01ede8b60373d9e3b566b78 + shared_preferences_macos: f3f29b71ccbb56bf40c9dd6396c9acf15e214087 + shared_preferences_web: 141cce0c3ed1a1c5bf2a0e44f52d31eeb66e5ea9 + shared_preferences_windows: 36b76d6f54e76ead957e60b49e2f124b4cd3e6ae + speech_to_text: b43a7d99aef037bd758ed8e45d79bbac035d2dfe + sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 + SwiftyGif: 5d4af95df24caf1c570dbbcb32a3b8a0763bc6d7 + TOCropViewController: da59f531f8ac8a94ef6d6c0fc34009350f9e8bfe + Try: 5ef669ae832617b3cee58cb2c6f99fb767a4ff96 + twilio_programmable_video: 6a41593640f3d86af60b22541fd457b22deaae7f + TwilioVideo: c13a51ceca375e91620eb7578d2573c90cf53b46 + url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef + url_launcher_linux: ac237cb7a8058736e4aae38bdbcc748a4b394cc0 + url_launcher_macos: fd7894421cd39320dce5f292fc99ea9270b2a313 + url_launcher_web: e5527357f037c87560776e36436bf2b0288b965c + url_launcher_windows: 683d7c283894db8d1914d3ab2223b20cc1ad95d5 + vibration: b5a33e764c3f609a975b9dca73dce20fdde627dc + vibration_web: 0ba303d92469ba34d71c612a228b315908d7fcd9 + video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e + video_player_web: da8cadb8274ed4f8dbee8d7171b420dedd437ce7 + wakelock: 0d4a70faf8950410735e3f61fb15d517c8a6efc4 + webview_flutter: d2b4d6c66968ad042ad94cbb791f5b72b4678a96 + wifi: d7d77c94109e36c4175d845f0a5964eadba71060 -PODFILE CHECKSUM: d94bd40f28772938199c67fcced06ffe96096c14 +PODFILE CHECKSUM: 5a17be3f8af73a757fa4439c77cf6ab2db29a6e7 COCOAPODS: 1.10.1 diff --git a/lib/config/config.dart b/lib/config/config.dart index cf1836ac..a167e1b5 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -8,9 +8,11 @@ import 'package:diplomaticquarterapp/widgets/mobile-no/mobile_no.dart'; const MAX_SMALL_SCREEN = 660; // PACKAGES and OFFERS -const EXA_CART_API_BASE_URL = 'https://mdlaboratories.com/exacartapi'; +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 BASE_URL = 'https://uat.hmgwebservices.com/'; // const BASE_URL = 'https://hmgwebservices.com/'; diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index 6ab1a723..fa4d06f7 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -578,6 +578,7 @@ const Map localizedValues = { "bestSellers": {"en": "Best Sellers", "ar": "أفضل البائعين"}, "deleteAllItems": {"en": "Delete All Items", "ar": "حذف كافة العناصر"}, "total": {"en": "Total", "ar": "المجموع"}, + "totalWithColonRight": {"en": "Total:", "ar": ":المجموع"}, "selectAddress": {"en": "Select Address", "ar": "حدد العنوان"}, "shippingAddress": {"en": "SHIPPING ADDRESS", "ar": "عنوان الشحن"}, "changeAddress": {"en": "Change Address", "ar": "تغيير العنوان"}, diff --git a/lib/core/model/packages_offers/requests/AddProductToCartRequestModel.dart b/lib/core/model/packages_offers/requests/AddProductToCartRequestModel.dart new file mode 100644 index 00000000..69e56ad7 --- /dev/null +++ b/lib/core/model/packages_offers/requests/AddProductToCartRequestModel.dart @@ -0,0 +1,26 @@ +import 'package:flutter/cupertino.dart'; + +class AddProductToCartRequestModel { + int quantity; + int product_id; + String shopping_cart_type; + int customer_id; + + AddProductToCartRequestModel({@required this.product_id, this.customer_id, this.shopping_cart_type = "ShoppingCart", this.quantity = 1}); + + Map json() { + return { + "shopping_cart_item" : { + "quantity": quantity, + "product_id": product_id, + "shopping_cart_type": shopping_cart_type, + "customer_id": customer_id + } + }; + } +} + +class UpdateProductToCartRequestModel extends AddProductToCartRequestModel{ + UpdateProductToCartRequestModel({@required int product_id, @required int customer_id, String shopping_cart_type = "ShoppingCart", int quantity = 1}) + : super(customer_id: customer_id, product_id: product_id, quantity: quantity, shopping_cart_type: shopping_cart_type); +} diff --git a/lib/core/model/packages_offers/requests/CreateCustomerRequestModel.dart b/lib/core/model/packages_offers/requests/CreateCustomerRequestModel.dart new file mode 100644 index 00000000..116545bd --- /dev/null +++ b/lib/core/model/packages_offers/requests/CreateCustomerRequestModel.dart @@ -0,0 +1,21 @@ +import 'package:flutter/cupertino.dart'; + +class PackagesCustomerRequestModel { + + String email; + String phoneNumber; + + PackagesCustomerRequestModel({@required this.email, @required this.phoneNumber}); + + Map json() { + return { + "customer" : { + "email": email, + "addresses": [{ + "email": email, + "phone_number": phoneNumber + }] + } + }; + } +} \ No newline at end of file diff --git a/lib/core/model/packages_offers/requests/OffersCategoriesRequestModel.dart b/lib/core/model/packages_offers/requests/OffersCategoriesRequestModel.dart index f2f4af11..13dba945 100644 --- a/lib/core/model/packages_offers/requests/OffersCategoriesRequestModel.dart +++ b/lib/core/model/packages_offers/requests/OffersCategoriesRequestModel.dart @@ -6,6 +6,12 @@ class OffersCategoriesRequestModel { OffersCategoriesRequestModel({this.limit, this.page, this.sinceId}); Map toFlatMap() { - return {"limit": limit.toString(), "page": page.toString(), "sinceId": sinceId.toString()}; + return { + if(limit != null && limit > 0) + "limit": limit.toString(), + + if(page != null && page > 0) + "page": page.toString(), + }; } } diff --git a/lib/core/model/packages_offers/requests/OffersProductsRequestModel.dart b/lib/core/model/packages_offers/requests/OffersProductsRequestModel.dart index 84862568..583932bb 100644 --- a/lib/core/model/packages_offers/requests/OffersProductsRequestModel.dart +++ b/lib/core/model/packages_offers/requests/OffersProductsRequestModel.dart @@ -1,12 +1,24 @@ class OffersProductsRequestModel { final int categoryId; final int limit; - final int page; - final int sinceId; + // final int page; + int sinceId; - OffersProductsRequestModel({this.categoryId, this.limit, this.page, this.sinceId}); + OffersProductsRequestModel({this.categoryId, this.limit = 50}); Map toFlatMap() { - return {"limit": limit.toString(), "page": page.toString(), "sinceId": sinceId.toString(), "categoryId": categoryId.toString()}; + return { + + if(limit != null && limit > 0) + "limit": limit.toString(), + + // if(page != null && page > 0) + // "page": page.toString(), + + if(categoryId != null && categoryId > 0) + "categoryId": categoryId.toString(), + + "sinceId": sinceId != null ? sinceId.toString() : "0", + }; } } diff --git a/lib/core/model/packages_offers/responses/PackagesCartItemsResponseModel.dart b/lib/core/model/packages_offers/responses/PackagesCartItemsResponseModel.dart new file mode 100644 index 00000000..9514976f --- /dev/null +++ b/lib/core/model/packages_offers/responses/PackagesCartItemsResponseModel.dart @@ -0,0 +1,132 @@ + +import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesResponseModel.dart'; + +class CartProductResponseModel { + int _quantity; + + set quantity(int value) { + _quantity = value; + } + + String _shoppingCartType; + int _productId; + PackagesResponseModel _product; + int _id; + + int get quantity => _quantity; + String get shoppingCartType => _shoppingCartType; + int get productId => _productId; + PackagesResponseModel get product => _product; + int get id => _id; + + CartProductResponseModel({ + int quantity, + String shoppingCartType, + int productId, + PackagesResponseModel product, + int id}){ + _quantity = quantity; + _shoppingCartType = shoppingCartType; + _productId = productId; + _product = product; + _id = id; +} + + CartProductResponseModel.fromJson(dynamic json) { + _quantity = json["quantity"]; + _shoppingCartType = json["shopping_cart_type"]; + _productId = json["product_id"]; + _product = json["product"] != null ? PackagesResponseModel().fromJson(json["product"]) : null; + _id = json["id"]; + } + + Map toJson() { + var map = {}; + map["quantity"] = _quantity; + map["shopping_cart_type"] = _shoppingCartType; + map["product_id"] = _productId; + if (_product != null) { + map["product"] = _product.toJson(); + } + map["id"] = _id; + return map; + } + +} + +class Images { + int _id; + int _pictureId; + int _position; + String _src; + dynamic _attachment; + + int get id => _id; + int get pictureId => _pictureId; + int get position => _position; + String get src => _src; + dynamic get attachment => _attachment; + + Images({ + int id, + int pictureId, + int position, + String src, + dynamic attachment}){ + _id = id; + _pictureId = pictureId; + _position = position; + _src = src; + _attachment = attachment; +} + + Images.fromJson(dynamic json) { + _id = json["id"]; + _pictureId = json["picture_id"]; + _position = json["position"]; + _src = json["src"]; + _attachment = json["attachment"]; + } + + Map toJson() { + var map = {}; + map["id"] = _id; + map["picture_id"] = _pictureId; + map["position"] = _position; + map["src"] = _src; + map["attachment"] = _attachment; + return map; + } + +} + +/// language_id : 1 +/// localized_name : "Dermatology testing" + +class Localized_names { + int _languageId; + String _localizedName; + + int get languageId => _languageId; + String get localizedName => _localizedName; + + Localized_names({ + int languageId, + String localizedName}){ + _languageId = languageId; + _localizedName = localizedName; +} + + Localized_names.fromJson(dynamic json) { + _languageId = json["language_id"]; + _localizedName = json["localized_name"]; + } + + Map toJson() { + var map = {}; + map["language_id"] = _languageId; + map["localized_name"] = _localizedName; + return map; + } + +} \ No newline at end of file diff --git a/lib/core/model/packages_offers/responses/OfferCategoriesResponseModel.dart b/lib/core/model/packages_offers/responses/PackagesCategoriesResponseModel.dart similarity index 82% rename from lib/core/model/packages_offers/responses/OfferCategoriesResponseModel.dart rename to lib/core/model/packages_offers/responses/PackagesCategoriesResponseModel.dart index 087f1961..292022c0 100644 --- a/lib/core/model/packages_offers/responses/OfferCategoriesResponseModel.dart +++ b/lib/core/model/packages_offers/responses/PackagesCategoriesResponseModel.dart @@ -1,8 +1,8 @@ import 'package:diplomaticquarterapp/generated/json/base/json_convert_content.dart'; import 'package:diplomaticquarterapp/generated/json/base/json_field.dart'; -class OfferCategoriesResponseModel with JsonConvert { - String id; +class PackagesCategoriesResponseModel with JsonConvert { + int id; String name; String namen; @JSONField(name: "localized_names") @@ -49,6 +49,18 @@ class OfferCategoriesResponseModel with JsonConvert { diff --git a/lib/core/model/packages_offers/responses/PackagesCustomerResponseModel.dart b/lib/core/model/packages_offers/responses/PackagesCustomerResponseModel.dart new file mode 100644 index 00000000..314b0ad3 --- /dev/null +++ b/lib/core/model/packages_offers/responses/PackagesCustomerResponseModel.dart @@ -0,0 +1,199 @@ +class PackagesCustomerResponseModel { + List _shoppingCartItems; + dynamic _billingAddress; + dynamic _shippingAddress; + List _addresses; + String _customerGuid; + dynamic _username; + String _email; + dynamic _firstName; + dynamic _lastName; + dynamic _languageId; + dynamic _dateOfBirth; + dynamic _gender; + dynamic _adminComment; + bool _isTaxExempt; + bool _hasShoppingCartItems; + bool _active; + bool _deleted; + bool _isSystemAccount; + dynamic _systemName; + dynamic _lastIpAddress; + String _createdOnUtc; + dynamic _lastLoginDateUtc; + String _lastActivityDateUtc; + int _registeredInStoreId; + bool _subscribedToNewsletter; + List _roleIds; + int _id; + + List get shoppingCartItems => _shoppingCartItems; + dynamic get billingAddress => _billingAddress; + dynamic get shippingAddress => _shippingAddress; + List get addresses => _addresses; + String get customerGuid => _customerGuid; + dynamic get username => _username; + String get email => _email; + dynamic get firstName => _firstName; + dynamic get lastName => _lastName; + dynamic get languageId => _languageId; + dynamic get dateOfBirth => _dateOfBirth; + dynamic get gender => _gender; + dynamic get adminComment => _adminComment; + bool get isTaxExempt => _isTaxExempt; + bool get hasShoppingCartItems => _hasShoppingCartItems; + bool get active => _active; + bool get deleted => _deleted; + bool get isSystemAccount => _isSystemAccount; + dynamic get systemName => _systemName; + dynamic get lastIpAddress => _lastIpAddress; + String get createdOnUtc => _createdOnUtc; + dynamic get lastLoginDateUtc => _lastLoginDateUtc; + String get lastActivityDateUtc => _lastActivityDateUtc; + int get registeredInStoreId => _registeredInStoreId; + bool get subscribedToNewsletter => _subscribedToNewsletter; + List get roleIds => _roleIds; + int get id => _id; + + PackagesCustomerResponseModel({ + List shoppingCartItems, + dynamic billingAddress, + dynamic shippingAddress, + List addresses, + String customerGuid, + dynamic username, + String email, + dynamic firstName, + dynamic lastName, + dynamic languageId, + dynamic dateOfBirth, + dynamic gender, + dynamic adminComment, + bool isTaxExempt, + bool hasShoppingCartItems, + bool active, + bool deleted, + bool isSystemAccount, + dynamic systemName, + dynamic lastIpAddress, + String createdOnUtc, + dynamic lastLoginDateUtc, + String lastActivityDateUtc, + int registeredInStoreId, + bool subscribedToNewsletter, + List roleIds, + int id}){ + _shoppingCartItems = shoppingCartItems; + _billingAddress = billingAddress; + _shippingAddress = shippingAddress; + _addresses = addresses; + _customerGuid = customerGuid; + _username = username; + _email = email; + _firstName = firstName; + _lastName = lastName; + _languageId = languageId; + _dateOfBirth = dateOfBirth; + _gender = gender; + _adminComment = adminComment; + _isTaxExempt = isTaxExempt; + _hasShoppingCartItems = hasShoppingCartItems; + _active = active; + _deleted = deleted; + _isSystemAccount = isSystemAccount; + _systemName = systemName; + _lastIpAddress = lastIpAddress; + _createdOnUtc = createdOnUtc; + _lastLoginDateUtc = lastLoginDateUtc; + _lastActivityDateUtc = lastActivityDateUtc; + _registeredInStoreId = registeredInStoreId; + _subscribedToNewsletter = subscribedToNewsletter; + _roleIds = roleIds; + _id = id; +} + + PackagesCustomerResponseModel.fromJson(dynamic json) { + _billingAddress = json["billing_address"]; + _shippingAddress = json["shipping_address"]; + _customerGuid = json["customer_guid"]; + _username = json["username"]; + _email = json["email"]; + _firstName = json["first_name"]; + _lastName = json["last_name"]; + _languageId = json["language_id"]; + _dateOfBirth = json["date_of_birth"]; + _gender = json["gender"]; + _adminComment = json["admin_comment"]; + _isTaxExempt = json["is_tax_exempt"]; + _hasShoppingCartItems = json["has_shopping_cart_items"]; + _active = json["active"]; + _deleted = json["deleted"]; + _isSystemAccount = json["is_system_account"]; + _systemName = json["system_name"]; + _lastIpAddress = json["last_ip_address"]; + _createdOnUtc = json["created_on_utc"]; + _lastLoginDateUtc = json["last_login_date_utc"]; + _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)); + // }); + // } + } + + Map toJson() { + var map = {}; + if (_shoppingCartItems != null) { + map["shopping_cart_items"] = _shoppingCartItems.map((v) => v.toJson()).toList(); + } + map["billing_address"] = _billingAddress; + map["shipping_address"] = _shippingAddress; + if (_addresses != null) { + map["addresses"] = _addresses.map((v) => v.toJson()).toList(); + } + map["customer_guid"] = _customerGuid; + map["username"] = _username; + map["email"] = _email; + map["first_name"] = _firstName; + map["last_name"] = _lastName; + map["language_id"] = _languageId; + map["date_of_birth"] = _dateOfBirth; + map["gender"] = _gender; + map["admin_comment"] = _adminComment; + map["is_tax_exempt"] = _isTaxExempt; + map["has_shopping_cart_items"] = _hasShoppingCartItems; + map["active"] = _active; + map["deleted"] = _deleted; + map["is_system_account"] = _isSystemAccount; + map["system_name"] = _systemName; + map["last_ip_address"] = _lastIpAddress; + map["created_on_utc"] = _createdOnUtc; + map["last_login_date_utc"] = _lastLoginDateUtc; + map["last_activity_date_utc"] = _lastActivityDateUtc; + map["registered_in_store_id"] = _registeredInStoreId; + map["subscribed_to_newsletter"] = _subscribedToNewsletter; + if (_roleIds != null) { + map["role_ids"] = _roleIds.map((v) => v.toJson()).toList(); + } + map["id"] = _id; + return map; + } + +} \ No newline at end of file diff --git a/lib/core/model/packages_offers/responses/OfferProductsResponseModel.dart b/lib/core/model/packages_offers/responses/PackagesResponseModel.dart similarity index 95% rename from lib/core/model/packages_offers/responses/OfferProductsResponseModel.dart rename to lib/core/model/packages_offers/responses/PackagesResponseModel.dart index 58481a8b..7297a20a 100644 --- a/lib/core/model/packages_offers/responses/OfferProductsResponseModel.dart +++ b/lib/core/model/packages_offers/responses/PackagesResponseModel.dart @@ -1,8 +1,8 @@ import 'package:diplomaticquarterapp/generated/json/base/json_convert_content.dart'; import 'package:diplomaticquarterapp/generated/json/base/json_field.dart'; -class OfferProductsResponseModel with JsonConvert { - String id; +class PackagesResponseModel with JsonConvert { + int id; @JSONField(name: "visible_individually") bool visibleIndividually; String name; @@ -205,6 +205,17 @@ class OfferProductsResponseModel with JsonConvert { int vendorId; @JSONField(name: "se_name") String seName; + + String getName() { + if(localizedNames.length == 2){ + if(localizedNames.first.languageId == 2) + return localizedNames.first.localizedName ?? name; + + else if(localizedNames.first.languageId == 1) + return localizedNames.last.localizedName ?? name; + } + return name; + } } class OfferProductsResponseModelLocalizedName with JsonConvert { diff --git a/lib/core/service/client/base_app_client.dart b/lib/core/service/client/base_app_client.dart index 429303bd..24fd202f 100644 --- a/lib/core/service/client/base_app_client.dart +++ b/lib/core/service/client/base_app_client.dart @@ -300,11 +300,45 @@ class BaseAppClient { } } + simplePost(String fullUrl, + { Map body, + Function(dynamic response, int statusCode) onSuccess, + Function(String error, int statusCode) onFailure,}) async { + + String url = fullUrl; + print("URL Query String: $url"); + + if (await Utils.checkConnection()) { + final response = await http.post( + url.trim(), + body: json.encode(body), + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + }, + ); + + final int statusCode = response.statusCode; + print("statusCode :$statusCode"); + + if (statusCode < 200 || statusCode >= 400 || json == null) { + onFailure('Error While Fetching data', statusCode); + } else { + onSuccess(response.body.toString(), statusCode); + } + } else { + onFailure('Please Check The Internet Connection', -1); + } + } + simpleGet(String fullUrl, {Function(dynamic response, int statusCode) onSuccess, - Function(String error, int statusCode) onFailure, - Map queryParams}) async { + Function(String error, int statusCode) onFailure, + Map queryParams}) async { + String url = fullUrl; + print("URL Query String: $url"); + var haveParams = (queryParams != null); if (haveParams) { String queryString = Uri(queryParameters: queryParams).query; @@ -334,6 +368,75 @@ class BaseAppClient { } } + + simplePut(String fullUrl, + { Map body, + Function(dynamic response, int statusCode) onSuccess, + Function(String error, int statusCode) onFailure}) async { + + String url = fullUrl; + print("URL Query String: $url"); + + if (await Utils.checkConnection()) { + final response = await http.put( + url.trim(), + body: json.encode(body), + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + }, + ); + + final int statusCode = response.statusCode; + print("statusCode :$statusCode"); + + if (statusCode < 200 || statusCode >= 400 || json == null) { + onFailure('Error While Fetching data', statusCode); + } else { + onSuccess(response.body.toString(), statusCode); + } + } else { + onFailure('Please Check The Internet Connection', -1); + } + } + + simpleDelete(String fullUrl, + {Function(dynamic response, int statusCode) onSuccess, + Function(String error, int statusCode) onFailure, + Map queryParams}) async { + + String url = fullUrl; + print("URL Query String: $url"); + + var haveParams = (queryParams != null); + if (haveParams) { + String queryString = Uri(queryParameters: queryParams).query; + url += '?' + queryString; + print("URL Query String: $url"); + } + + if (await Utils.checkConnection()) { + final response = await http.delete( + url.trim(), + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + }, + ); + + final int statusCode = response.statusCode; + print("statusCode :$statusCode"); + + if (statusCode < 200 || statusCode >= 400 || json == null) { + onFailure('Error While Fetching data', statusCode); + } else { + onSuccess(response.body.toString(), statusCode); + } + } else { + onFailure('Please Check The Internet Connection', -1); + } + } + logout() async { await sharedPref.remove(LOGIN_TOKEN_ID); await sharedPref.remove(PHARMACY_CUSTOMER_ID); diff --git a/lib/core/service/packages_offers/PackagesOffersServices.dart b/lib/core/service/packages_offers/PackagesOffersServices.dart index e58c3fa3..c0c7bc94 100644 --- a/lib/core/service/packages_offers/PackagesOffersServices.dart +++ b/lib/core/service/packages_offers/PackagesOffersServices.dart @@ -1,27 +1,42 @@ import 'dart:convert'; import 'dart:developer'; +import 'dart:ui'; import 'package:diplomaticquarterapp/config/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/OfferCategoriesResponseModel.dart'; -import 'package:diplomaticquarterapp/core/model/packages_offers/responses/OfferProductsResponseModel.dart'; +import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesCartItemsResponseModel.dart'; +import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesCategoriesResponseModel.dart'; +import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesResponseModel.dart'; +import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesCustomerResponseModel.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'; +import 'package:flutter/cupertino.dart'; import '../../../locator.dart'; class OffersAndPackagesServices extends BaseService { - List categoryList = List(); + List categoryList = List(); + List productList = List(); + List latestOffersList = List(); + List bestSellerList = List(); + List bannersList = List(); + List cartItemList = List(); + + PackagesCustomerResponseModel customer; + + Future> getAllCategories(OffersCategoriesRequestModel request) async { + Future errorThrow; - Future> getAllCategories(OffersCategoriesRequestModel request) async { - hasError = false; var url = EXA_CART_API_BASE_URL + PACKAGES_CATEGORIES; await baseAppClient.simpleGet(url, onSuccess: (dynamic stringResponse, int statusCode) { if (statusCode == 200) { var jsonResponse = json.decode(stringResponse); jsonResponse['categories'].forEach((json) { - categoryList.add(OfferCategoriesResponseModel().fromJson(json)); + categoryList.add(PackagesCategoriesResponseModel().fromJson(json)); }); } }, onFailure: (String error, int statusCode) { @@ -31,15 +46,18 @@ class OffersAndPackagesServices extends BaseService { return categoryList; } - List productList = List(); - Future> getAllProducts(OffersProductsRequestModel request) async { - hasError = false; + Future> getAllProducts({@required OffersProductsRequestModel request, @required BuildContext context, @required bool showLoading = true}) async { + Future errorThrow; + + request.sinceId = (productList.isNotEmpty) ? productList.last.id : 0; + + productList = List(); var url = EXA_CART_API_BASE_URL + PACKAGES_PRODUCTS; await baseAppClient.simpleGet(url, onSuccess: (dynamic stringResponse, int statusCode) { if (statusCode == 200) { var jsonResponse = json.decode(stringResponse); jsonResponse['products'].forEach((json) { - productList.add(OfferProductsResponseModel().fromJson(json)); + productList.add(PackagesResponseModel().fromJson(json)); }); } }, onFailure: (String error, int statusCode) { @@ -48,4 +66,241 @@ class OffersAndPackagesServices extends BaseService { return productList; } + + Future> getLatestOffers({@required OffersProductsRequestModel request, @required BuildContext context, @required bool showLoading = true}) async { + + var url = EXA_CART_API_BASE_URL + PACKAGES_PRODUCTS; + await baseAppClient.simpleGet(url, onSuccess: (dynamic stringResponse, int statusCode) { + if (statusCode == 200) { + var jsonResponse = json.decode(stringResponse); + jsonResponse['products'].forEach((json) { + latestOffersList.add(PackagesResponseModel().fromJson(json)); + }); + } + }, onFailure: (String error, int statusCode) { + log(error); + }, queryParams: request.toFlatMap()); + + return latestOffersList; + } + + Future> getBestSellers({@required OffersProductsRequestModel request, @required BuildContext context, @required bool showLoading = true}) async { + + var url = EXA_CART_API_BASE_URL + PACKAGES_PRODUCTS; + await baseAppClient.simpleGet(url, onSuccess: (dynamic stringResponse, int statusCode) { + if (statusCode == 200) { + var jsonResponse = json.decode(stringResponse); + jsonResponse['products'].forEach((json) { + bestSellerList.add(PackagesResponseModel().fromJson(json)); + }); + } + }, onFailure: (String error, int statusCode) { + log(error); + }, queryParams: request.toFlatMap()); + + return bestSellerList; + } + + + Future> getBanners({@required OffersProductsRequestModel request, @required BuildContext context, @required bool showLoading = true}) async { + var url = EXA_CART_API_BASE_URL + PACKAGES_PRODUCTS; + await baseAppClient.simpleGet(url, onSuccess: (dynamic stringResponse, int statusCode) { + if (statusCode == 200) { + var jsonResponse = json.decode(stringResponse); + jsonResponse['products'].forEach((json) { + bannersList.add(PackagesResponseModel().fromJson(json)); + }); + } + }, onFailure: (String error, int statusCode) { + log(error); + }, queryParams: request.toFlatMap()); + + return bannersList; + } + + Future loadOffersPackagesDataForMainPage({@required BuildContext context, bool showLoading = true, Function completion }) async { + var finished = 0; + var totalCalls = 3; + + completedAll(){ + + finished++; + if(completion != null && finished == totalCalls) { + _hideLoading(context, showLoading); + completion(); + } + } + + _showLoading(context, showLoading); + + // Performing Parallel Request on same time + // # 1 + getBestSellers(request: OffersProductsRequestModel(), context: context, showLoading: false).then((value){ + completedAll(); + }); + + // # 2 + getLatestOffers(request: OffersProductsRequestModel(), context: context, showLoading: false).then((value){ + completedAll(); + }); + + // # 3 + getBanners(request: OffersProductsRequestModel(), context: context, showLoading: false).then((value){ + completedAll(); + }); + + } + + // -------------------- + // Create Customer + // -------------------- + 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; + _showLoading(context, showLoading); + await baseAppClient.simplePost(url, body: request.json(), onSuccess: (dynamic stringResponse, int statusCode){ + _hideLoading(context, showLoading); + + var jsonResponse = json.decode(stringResponse); + var customerJson = jsonResponse['customers'].first; + customer = PackagesCustomerResponseModel.fromJson(customerJson); + + }, onFailure: (String error, int statusCode){ + _hideLoading(context, showLoading); + log(error); + }); + + return customer; + } + + + + // -------------------- + // Shopping Cart + // -------------------- + Future> cartItems({@required BuildContext context, bool showLoading = true}) async{ + Future errorThrow; + + cartItemList.clear(); + _showLoading(context, showLoading); + var url = EXA_CART_API_BASE_URL + PACKAGES_SHOPPING_CART + '/${customer.id}'; + await baseAppClient.simpleGet(url, onSuccess: (dynamic stringResponse, int statusCode) { + _hideLoading(context, showLoading); + + var jsonResponse = json.decode(stringResponse); + jsonResponse['shopping_carts'].forEach((json) { + cartItemList.add(CartProductResponseModel.fromJson(json)); + }); + + }, onFailure: (String error, int statusCode) { + _hideLoading(context, showLoading); + log(error); + errorThrow = Future.error({"error":error, "statusCode":statusCode}); + }, queryParams: null); + + return errorThrow ?? cartItemList; + } + + Future addProductToCart(AddProductToCartRequestModel request, {@required BuildContext context, bool showLoading = true}) async{ + Future errorThrow; + + request.customer_id = customer.id; + + _showLoading(context, showLoading); + var url = EXA_CART_API_BASE_URL + PACKAGES_SHOPPING_CART; + await baseAppClient.simplePost(url, body: request.json(), onSuccess: (dynamic stringResponse, int statusCode){ + _hideLoading(context, showLoading); + + var jsonResponse = json.decode(stringResponse); + + }, onFailure: (String error, int statusCode){ + _hideLoading(context, showLoading); + log(error); + errorThrow = Future.error(error); + }); + + return errorThrow ?? true; + } + + Future updateProductToCart(int cartItemID, {UpdateProductToCartRequestModel request, @required BuildContext context, bool showLoading = true}) async{ + Future errorThrow; + + _showLoading(context, showLoading); + var url = EXA_CART_API_BASE_URL + PACKAGES_SHOPPING_CART + '/$cartItemID'; + await baseAppClient.simplePut(url, body: request.json(), onSuccess: (dynamic stringResponse, int statusCode){ + _hideLoading(context, showLoading); + + var jsonResponse = json.decode(stringResponse); + + }, onFailure: (String error, int statusCode){ + _hideLoading(context, showLoading); + log(error); + errorThrow = Future.error({"error":error, "statusCode":statusCode}); + }); + + return errorThrow ?? bannersList; + } + + + Future deleteProductFromCart(int cartItemID, {@required BuildContext context, bool showLoading = true}) async{ + Future errorThrow; + + _showLoading(context, showLoading); + var url = EXA_CART_API_BASE_URL + PACKAGES_SHOPPING_CART + '/$cartItemID'; + await baseAppClient.simpleDelete(url, onSuccess: (dynamic stringResponse, int statusCode){ + _hideLoading(context, showLoading); + // var jsonResponse = json.decode(stringResponse); + + }, onFailure: (String error, int statusCode){ + _hideLoading(context, showLoading); + log(error); + errorThrow = Future.error({"error":error, "statusCode":statusCode}); + }); + + return errorThrow ?? true; + } + + // -------------------- + // Place Order + // -------------------- + Future placeOrder({@required BuildContext context, bool showLoading = true}) async{ + Future errorThrow; + + var jsonBody = { + "order": { + "customer_id" : customer.id + } + }; + + _showLoading(context, showLoading); + var url = EXA_CART_API_BASE_URL + PACKAGES_SHOPPING_CART; + await baseAppClient.simplePost(url, body: jsonBody, onSuccess: (dynamic stringResponse, int statusCode){ + _hideLoading(context, showLoading); + + var jsonResponse = json.decode(stringResponse); + + }, onFailure: (String error, int statusCode){ + _hideLoading(context, showLoading); + log(error); + errorThrow = Future.error(error); + }); + + return errorThrow ?? true; + } + } + +_showLoading(BuildContext context, bool flag){ + if(flag) + GifLoaderDialogUtils.showMyDialog(context); +} + +_hideLoading(BuildContext context, bool flag){ + if(flag) + GifLoaderDialogUtils.hideDialog(context); +} \ No newline at end of file diff --git a/lib/core/viewModels/packages_offers/PackagesOffersViewModel.dart b/lib/core/viewModels/packages_offers/PackagesOffersViewModel.dart index 21df52bc..83e104dc 100644 --- a/lib/core/viewModels/packages_offers/PackagesOffersViewModel.dart +++ b/lib/core/viewModels/packages_offers/PackagesOffersViewModel.dart @@ -1,6 +1,7 @@ import 'package:diplomaticquarterapp/core/enum/viewstate.dart'; -import 'package:diplomaticquarterapp/core/model/packages_offers/responses/OfferCategoriesResponseModel.dart'; -import 'package:diplomaticquarterapp/core/model/packages_offers/responses/OfferProductsResponseModel.dart'; +import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesCartItemsResponseModel.dart'; +import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesCategoriesResponseModel.dart'; +import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesResponseModel.dart'; import 'package:diplomaticquarterapp/core/service/base_service.dart'; import 'package:diplomaticquarterapp/core/service/client/base_app_client.dart'; import 'package:diplomaticquarterapp/core/service/packages_offers/PackagesOffersServices.dart'; @@ -10,10 +11,16 @@ import 'package:diplomaticquarterapp/locator.dart'; class OfferCategoriesViewModel extends BaseViewModel { OffersAndPackagesServices service = locator(); - List get list => service.categoryList; + get categoryList => service.categoryList; + get productList => service.categoryList; } -class OfferProductsViewModel extends BaseViewModel { +class PackagesViewModel extends BaseViewModel { OffersAndPackagesServices service = locator(); - List get list => service.productList; + List get categoryList => service.categoryList; + List get productList => service.productList; + List get latestOffersList => service.latestOffersList; + List get bestSellerList => service.bestSellerList; + List get bannersList => service.bannersList; + List get cartItemList => service.cartItemList; } diff --git a/lib/generated/json/OfferCategoriesResponseModel_helper.dart b/lib/generated/json/OfferCategoriesResponseModel_helper.dart index e5ebc914..1a28d179 100644 --- a/lib/generated/json/OfferCategoriesResponseModel_helper.dart +++ b/lib/generated/json/OfferCategoriesResponseModel_helper.dart @@ -1,8 +1,8 @@ -import 'package:diplomaticquarterapp/core/model/packages_offers/responses/OfferCategoriesResponseModel.dart'; +import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesCategoriesResponseModel.dart'; -offerCategoriesResponseModelFromJson(OfferCategoriesResponseModel data, Map json) { +offerCategoriesResponseModelFromJson(PackagesCategoriesResponseModel data, Map json) { if (json['id'] != null) { - data.id = json['id']?.toString(); + data.id = json['id']; } if (json['name'] != null) { data.name = json['name']?.toString(); @@ -91,7 +91,7 @@ offerCategoriesResponseModelFromJson(OfferCategoriesResponseModel data, Map offerCategoriesResponseModelToJson(OfferCategoriesResponseModel entity) { +Map offerCategoriesResponseModelToJson(PackagesCategoriesResponseModel entity) { final Map data = new Map(); data['id'] = entity.id; data['name'] = entity.name; diff --git a/lib/generated/json/OfferProductsResponseModel_helper.dart b/lib/generated/json/OfferProductsResponseModel_helper.dart index dc0edeca..d180af67 100644 --- a/lib/generated/json/OfferProductsResponseModel_helper.dart +++ b/lib/generated/json/OfferProductsResponseModel_helper.dart @@ -1,8 +1,8 @@ -import 'package:diplomaticquarterapp/core/model/packages_offers/responses/OfferProductsResponseModel.dart'; +import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesResponseModel.dart'; -offerProductsResponseModelFromJson(OfferProductsResponseModel data, Map json) { +offerProductsResponseModelFromJson(PackagesResponseModel data, Map json) { if (json['id'] != null) { - data.id = json['id']?.toString(); + data.id = json['id']; } if (json['visible_individually'] != null) { data.visibleIndividually = json['visible_individually']; @@ -353,7 +353,7 @@ offerProductsResponseModelFromJson(OfferProductsResponseModel data, Map offerProductsResponseModelToJson(OfferProductsResponseModel entity) { +Map offerProductsResponseModelToJson(PackagesResponseModel entity) { final Map data = new Map(); data['id'] = entity.id; data['visible_individually'] = entity.visibleIndividually; diff --git a/lib/generated/json/base/json_convert_content.dart b/lib/generated/json/base/json_convert_content.dart index 9fab946e..ae4eadeb 100644 --- a/lib/generated/json/base/json_convert_content.dart +++ b/lib/generated/json/base/json_convert_content.dart @@ -3,11 +3,11 @@ // ignore_for_file: prefer_single_quotes // This file is automatically generated. DO NOT EDIT, all your changes would be lost. -import 'package:diplomaticquarterapp/core/model/packages_offers/responses/OfferCategoriesResponseModel.dart'; +import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesCategoriesResponseModel.dart'; import 'package:diplomaticquarterapp/generated/json/OfferCategoriesResponseModel_helper.dart'; import 'package:diplomaticquarterapp/core/model/geofencing/responses/LogGeoZoneResponseModel.dart'; import 'package:diplomaticquarterapp/generated/json/log_geo_zone_response_model_entity_helper.dart'; -import 'package:diplomaticquarterapp/core/model/packages_offers/responses/OfferProductsResponseModel.dart'; +import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesResponseModel.dart'; import 'package:diplomaticquarterapp/generated/json/OfferProductsResponseModel_helper.dart'; import 'package:diplomaticquarterapp/core/model/geofencing/responses/GeoZonesResponseModel.dart'; import 'package:diplomaticquarterapp/generated/json/GeoZonesResponseModel_helper.dart'; @@ -23,16 +23,16 @@ class JsonConvert { static _getFromJson(Type type, data, json) { switch (type) { - case OfferCategoriesResponseModel: - return offerCategoriesResponseModelFromJson(data as OfferCategoriesResponseModel, json) as T; + case PackagesCategoriesResponseModel: + return offerCategoriesResponseModelFromJson(data as PackagesCategoriesResponseModel, json) as T; case OfferCategoriesResponseModelLocalizedName: return offerCategoriesResponseModelLocalizedNameFromJson(data as OfferCategoriesResponseModelLocalizedName, json) as T; case OfferCategoriesResponseModelImage: return offerCategoriesResponseModelImageFromJson(data as OfferCategoriesResponseModelImage, json) as T; case LogGeoZoneResponseModel: return logGeoZoneResponseModelEntityFromJson(data as LogGeoZoneResponseModel, json) as T; - case OfferProductsResponseModel: - return offerProductsResponseModelFromJson(data as OfferProductsResponseModel, json) as T; + case PackagesResponseModel: + return offerProductsResponseModelFromJson(data as PackagesResponseModel, json) as T; case OfferProductsResponseModelLocalizedName: return offerProductsResponseModelLocalizedNameFromJson(data as OfferProductsResponseModelLocalizedName, json) as T; case OfferProductsResponseModelImage: @@ -47,16 +47,16 @@ class JsonConvert { static _getToJson(Type type, data) { switch (type) { - case OfferCategoriesResponseModel: - return offerCategoriesResponseModelToJson(data as OfferCategoriesResponseModel); + case PackagesCategoriesResponseModel: + return offerCategoriesResponseModelToJson(data as PackagesCategoriesResponseModel); case OfferCategoriesResponseModelLocalizedName: return offerCategoriesResponseModelLocalizedNameToJson(data as OfferCategoriesResponseModelLocalizedName); case OfferCategoriesResponseModelImage: return offerCategoriesResponseModelImageToJson(data as OfferCategoriesResponseModelImage); case LogGeoZoneResponseModel: return logGeoZoneResponseModelEntityToJson(data as LogGeoZoneResponseModel); - case OfferProductsResponseModel: - return offerProductsResponseModelToJson(data as OfferProductsResponseModel); + case PackagesResponseModel: + return offerProductsResponseModelToJson(data as PackagesResponseModel); case OfferProductsResponseModelLocalizedName: return offerProductsResponseModelLocalizedNameToJson(data as OfferProductsResponseModelLocalizedName); case OfferProductsResponseModelImage: @@ -72,16 +72,16 @@ class JsonConvert { //Go back to a single instance by type static _fromJsonSingle(json) { String type = M.toString(); - if (type == (OfferCategoriesResponseModel).toString()) { - return OfferCategoriesResponseModel().fromJson(json); + if (type == (PackagesCategoriesResponseModel).toString()) { + return PackagesCategoriesResponseModel().fromJson(json); } else if (type == (OfferCategoriesResponseModelLocalizedName).toString()) { return OfferCategoriesResponseModelLocalizedName().fromJson(json); } else if (type == (OfferCategoriesResponseModelImage).toString()) { return OfferCategoriesResponseModelImage().fromJson(json); } else if (type == (LogGeoZoneResponseModel).toString()) { return LogGeoZoneResponseModel().fromJson(json); - } else if (type == (OfferProductsResponseModel).toString()) { - return OfferProductsResponseModel().fromJson(json); + } else if (type == (PackagesResponseModel).toString()) { + return PackagesResponseModel().fromJson(json); } else if (type == (OfferProductsResponseModelLocalizedName).toString()) { return OfferProductsResponseModelLocalizedName().fromJson(json); } else if (type == (OfferProductsResponseModelImage).toString()) { @@ -96,16 +96,16 @@ class JsonConvert { //list is returned by type static M _getListChildType(List data) { - if (List() is M) { - return data.map((e) => OfferCategoriesResponseModel().fromJson(e)).toList() as M; + if (List() is M) { + return data.map((e) => PackagesCategoriesResponseModel().fromJson(e)).toList() as M; } else if (List() is M) { return data.map((e) => OfferCategoriesResponseModelLocalizedName().fromJson(e)).toList() as M; } else if (List() is M) { return data.map((e) => OfferCategoriesResponseModelImage().fromJson(e)).toList() as M; } else if (List() is M) { return data.map((e) => LogGeoZoneResponseModel().fromJson(e)).toList() as M; - } else if (List() is M) { - return data.map((e) => OfferProductsResponseModel().fromJson(e)).toList() as M; + } else if (List() is M) { + return data.map((e) => PackagesResponseModel().fromJson(e)).toList() as M; } else if (List() is M) { return data.map((e) => OfferProductsResponseModelLocalizedName().fromJson(e)).toList() as M; } else if (List() is M) { diff --git a/lib/locator.dart b/lib/locator.dart index 4d7f1e50..bf97537d 100644 --- a/lib/locator.dart +++ b/lib/locator.dart @@ -282,12 +282,9 @@ void setupLocator() { // Offer And Packages //---------------------- - locator.registerLazySingleton( - () => OffersAndPackagesServices()); // offerPackagesServices Service - locator.registerFactory( - () => OfferCategoriesViewModel()); // Categories View Model - locator - .registerFactory(() => OfferProductsViewModel()); // Products View Model + locator.registerLazySingleton(() => OffersAndPackagesServices()); // offerPackagesServices Service + locator.registerFactory(() => OfferCategoriesViewModel()); // Categories View Model + locator.registerFactory(() => PackagesViewModel()); // Products View Model // Geofencing // --------------------- diff --git a/lib/main.dart b/lib/main.dart index e0444a32..05615a68 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -115,7 +115,8 @@ class MyApp extends StatelessWidget { ), ), ), - initialRoute: SPLASH, + // initialRoute: SPLASH, + initialRoute: PACKAGES_OFFERS, routes: routes, debugShowCheckedModeBanner: false, ), diff --git a/lib/pages/packages_offers/ClinicOfferAndPackagesPage.dart b/lib/pages/packages_offers/ClinicOfferAndPackagesPage.dart new file mode 100644 index 00000000..b1e447ef --- /dev/null +++ b/lib/pages/packages_offers/ClinicOfferAndPackagesPage.dart @@ -0,0 +1,80 @@ +import 'package:carousel_slider/carousel_slider.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'; +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/OfferAndPackageDetailPage.dart'; +import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; +import 'package:diplomaticquarterapp/uitl/utils.dart' as utils; +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'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; + +dynamic languageID; + +class ClinicPackagesPage extends StatefulWidget { + List products; + ClinicPackagesPage({@required this.products}); + + @override + _ClinicPackagesPageState createState() => _ClinicPackagesPageState(); + + +} + +class _ClinicPackagesPageState extends State { + List get _products => widget.products; + + PackagesViewModel viewModel; + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + + return BaseView( + allowAny: true, + onModelReady: (model){ + viewModel = model; + }, + builder: (_, model, wi) => AppScaffold( + appBarTitle: TranslationBase.of(context).offerAndPackages, + isShowAppBar: true, + isPharmacy: false, + showPharmacyCart: false, + showHomeAppBarIcon: false, + isOfferPackages: true, + showOfferPackagesCart: true, + isShowDecPage: false, + body: Padding( + padding: const EdgeInsets.all(5), + child: StaggeredGridView.countBuilder( + crossAxisCount:4, + itemCount: _products.length, + itemBuilder: (BuildContext context, int index) => new Container( + color: Colors.transparent, + child: PackagesItemCard( itemContentPadding: 10,itemModel: _products[index],) + ), + staggeredTileBuilder: (int index) => StaggeredTile.fit(2), + mainAxisSpacing: 20, + crossAxisSpacing: 10, + ) + ), + ), + ); + } + +} diff --git a/lib/pages/packages_offers/OfferAndPackageDetailPage.dart b/lib/pages/packages_offers/OfferAndPackageDetailPage.dart new file mode 100644 index 00000000..a6711ded --- /dev/null +++ b/lib/pages/packages_offers/OfferAndPackageDetailPage.dart @@ -0,0 +1,228 @@ +import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; +import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesCategoriesResponseModel.dart'; +import 'package:diplomaticquarterapp/core/viewModels/packages_offers/PackagesOffersViewModel.dart'; +import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/order_model_view_model.dart'; +import 'package:diplomaticquarterapp/pages/base/base_view.dart'; +import 'package:diplomaticquarterapp/pages/pharmacies/ProductCheckTypeWidget.dart'; +import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; +import 'package:diplomaticquarterapp/uitl/utils.dart' as utils; +import 'package:diplomaticquarterapp/widgets/others/StarRating.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +import 'ClinicOfferAndPackagesPage.dart'; + +class OfferAndPackagesDetail extends StatefulWidget{ + final dynamic model; + + const OfferAndPackagesDetail({@required this.model, Key key}) : super(key: key); + + @override + State createState() => OfferAndPackagesDetailState(); +} + + +class OfferAndPackagesDetailState extends State{ + + PackagesViewModel viewModel; + + @override + Widget build(BuildContext context) { + getLanguageID(); + + return BaseView( + onModelReady: (model){ + viewModel = model; + }, + builder: (_, model, wi) => AppScaffold( + appBarTitle: TranslationBase.of(context).offerAndPackages, + isShowAppBar: true, + isPharmacy: false, + showPharmacyCart: false, + showHomeAppBarIcon: false, + isOfferPackages: true, + showOfferPackagesCart: true, + isShowDecPage: false, + body: Stack( + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 60), + child: ListView( + children: [ + Padding( + padding: const EdgeInsets.all(5), + child: Stack( + children: [ + Padding( + padding: const EdgeInsets.all(10), + child: AspectRatio( + aspectRatio: 1/1, + child: utils.applyShadow( + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: utils.Utils.loadNetworkImage(url: "https://wallpaperaccess.com/full/30103.jpg",) + ), + ) + ), + ), + Align( + alignment: Alignment.topLeft, + child: Image.asset( + 'assets/images/discount_${'en'}.png', + height: 70, + width: 70, + ), + ), + + ], + + ), + ), + + Padding( + padding: const EdgeInsets.only(left: 20, right: 20, bottom: 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Child Dental Offer", + style: TextStyle( + fontWeight: FontWeight.normal, + color: Colors.black, + fontSize: 25 + ) + ), + + Stack( + children: [ + Text( + "200 SAR", + style: TextStyle( + fontWeight: FontWeight.normal, + decoration: TextDecoration.lineThrough, + color: Colors.grey, + fontSize: 12 + ) + ), + Padding( + padding: const EdgeInsets.only(top: 15), + child: Text( + "894.99 SAR", + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.green, + fontSize: 18 + ) + ), + ), + ], + ), + + StarRating( + size: 20, + totalCount: null, + totalAverage: 5, + forceStars: true), + + + SizedBox(height: 20,), + + + Text( + "Details", + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.grey, + fontSize: 20 + ) + ), + + + + AspectRatio( + aspectRatio: 2/1, + child: Container( + color: Colors.grey[300], + child: Padding( + padding: const EdgeInsets.all(10), + child: Text("Detail of offers written here ss"), + ) + ), + ), + + + SizedBox(height: 10,), + ], + ), + ), + ], + ), + ), + + Padding( + padding: const EdgeInsets.all(10), + child: Align( + alignment: Alignment.bottomRight, + child: Row( + children: [ + + Expanded( + child: RaisedButton.icon( + padding: EdgeInsets.only(top: 5, bottom: 5, left: 0, right: 0), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), + side: BorderSide(color: Colors.red, width: 0.5) + ), + color: Colors.red, + icon: Icon( + Icons.add_shopping_cart_outlined, + size: 25, + color: Colors.white, + ), + label: Text( + "Add to Cart", + style: TextStyle(fontSize: 17, color: Colors.white, fontWeight: FontWeight.normal), + ), + onPressed: (){},), + ), + + SizedBox(width: 15,), + + Expanded( + child: OutlineButton.icon( + padding: EdgeInsets.only(top: 5, bottom: 5, left: 0, right: 0), + borderSide: BorderSide(width: 1.0, color: Colors.red), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), + ), + color: Colors.white, + icon: Icon( + Icons.favorite_rounded, + size: 25, + color: Colors.red, + ), + label: Text( + "Add to Favorites", + style: TextStyle(fontSize: 17, color: Colors.red, fontWeight: FontWeight.normal), + ), + onPressed: (){ + + },), + ), + + ], + ), + ), + ) + + + + ], + ) + ), + ); + } +} + diff --git a/lib/pages/packages_offers/OfferAndPackagesCartPage.dart b/lib/pages/packages_offers/OfferAndPackagesCartPage.dart new file mode 100644 index 00000000..98f237f6 --- /dev/null +++ b/lib/pages/packages_offers/OfferAndPackagesCartPage.dart @@ -0,0 +1,376 @@ +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/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/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/loadings/ShimmerLoading.dart'; +import 'package:diplomaticquarterapp/widgets/offers_packages/PackagesCartItemCard.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:diplomaticquarterapp/widgets/transitions/fade_page.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'; +import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; + +dynamic languageID; +const _columnCount = 1; + +AnimationController _animationController; + +class PackagesCartPage extends StatefulWidget { + PackagesCartPage(); + + @override + _PackagesCartPageState createState() => _PackagesCartPageState(); +} + +class _PackagesCartPageState extends State with AfterLayoutMixin, SingleTickerProviderStateMixin { + getLanguageID() async { + languageID = await sharedPref.getString(APP_LANGUAGE); + } + + @override + void initState() { + _agreeTerms = false; + _selectedPaymentMethod = null; + _animationController = AnimationController(vsync: this, duration: Duration(seconds: 500)); + super.initState(); + } + + @override + void dispose() { + _animationController.dispose(); + viewModel.cartItemList.clear(); + super.dispose(); + } + + PackagesViewModel viewModel; + + bool loadWidgets = false; + + onTermsClick(bool isAgree) { + setState(() => _agreeTerms = isAgree); + } + + onTermsInfoClick() { + Navigator.push(context, FadePage(page: PharmacyTermsConditions())); + } + + onPayNowClick() async{ + await viewModel.service.placeOrder(context: context); + } + + @override + void afterFirstLayout(BuildContext context) { + fetchData(); + } + + @override + Widget build(BuildContext context) { + return BaseView( + 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: false, + isShowDecPage: false, + body: Column( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.all(5), + child: StaggeredGridView.countBuilder( + crossAxisCount: (_columnCount * _columnCount), + itemCount: viewModel.cartItemList.length, + itemBuilder: (BuildContext context, int index) { + + var item = viewModel.cartItemList[index]; + return Dismissible( + key: Key(index.toString()), + direction: DismissDirection.startToEnd, + background: _cartItemDeleteContainer(), + secondaryBackground: _cartItemDeleteContainer(), + confirmDismiss: (direction) async { + bool status = await viewModel.service.deleteProductFromCart(item.id, context: context, showLoading: false); + return status; + }, + onDismissed: (direction) { + debugPrint('Index: $index'); + viewModel.cartItemList.removeAt(index); + }, + child: PackagesCartItemCard( + 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){ + utils.Utils.showErrorToast(error); + }); + return success ?? false; + }, + ) + ); + }, + staggeredTileBuilder: (int index) => StaggeredTile.fit(_columnCount), + mainAxisSpacing: 0, + crossAxisSpacing: 10, + )), + ), + Container( + height: 0.25, + color: Theme.of(context).primaryColor, + ), + Container( + color: Colors.white, + child: Column( + children: [ + Text( + TranslationBase.of(context).selectPaymentOption, + style: TextStyle( + fontSize: 10, + fontWeight: FontWeight.bold + ), + ), + + Container(height: 0.25, width: 100, color: Colors.grey[300],), + + _paymentOptions(context, (paymentMethod) { + setState(() => _selectedPaymentMethod = paymentMethod); + }), + + Container(height: 0.25, color: Colors.grey[300],), + + Container(height: 40, + child: _termsAndCondition(context, onSelected: onTermsClick, onInfoClick: onTermsInfoClick) + ), + + Container(height: 0.25, color: Colors.grey[300],), + _payNow(context, onPayNowClick: onPayNowClick) + ], + ), + ) + ], + ), + ); + }); + } + + fetchData() async { + await viewModel.service.cartItems(context: context).catchError((error) {}); + setState((){}); + } +} + +// /* Payment Footer Widgets */ +// --------------------------- +String _selectedPaymentMethod; +Widget _paymentOptions(BuildContext context, Function(String) onSelected) { + double height = 22; + + Widget buttonContent(bool isSelected, String imageName) { + return Container( + decoration: BoxDecoration( + color: Colors.white, + boxShadow: [ + BoxShadow( + color: isSelected ? Colors.green[50] : Colors.grey[200], + blurRadius: 1, + spreadRadius: 2, + ), + ], + borderRadius: BorderRadius.all(Radius.circular(5)), + border: Border.all(color: isSelected ? Colors.green : Colors.grey, width: isSelected ? 1 : 0.5) + ), + child: Padding( + padding: const EdgeInsets.all(4), + child: Image.asset('assets/images/new-design/$imageName'), + ) + ); + } + + return Padding( + padding: const EdgeInsets.all(5), + child: Container( + height: height, + color: Colors.transparent, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + InkWell( + child: buttonContent(_selectedPaymentMethod == "mada", 'mada.png'), + onTap: () { + onSelected("mada"); + }, + ), + SizedBox( + width: 5, + ), + InkWell( + child: buttonContent(_selectedPaymentMethod == "visa", 'visa.png'), + onTap: () { + onSelected("visa"); + }, + ), + SizedBox( + width: 5, + ), + InkWell( + child: buttonContent(_selectedPaymentMethod == "mastercard", 'mastercard.png'), + onTap: () { + onSelected("mastercard"); + }, + ), + SizedBox( + width: 5, + ), + InkWell( + child: buttonContent(_selectedPaymentMethod == "installment", 'installment.png'), + onTap: () { + onSelected("installment"); + }, + ), + ], + ), + ), + ); +} + +bool _agreeTerms = false; +Widget _termsAndCondition(BuildContext context, {@required Function(bool) onSelected, @required VoidCallback onInfoClick}) { + return Padding( + padding: const EdgeInsets.all(5), + child: Row( + children: [ + InkWell( + child: Icon( + _agreeTerms ? Icons.check_circle : Icons.radio_button_unchecked_sharp, + size: 20, + color: _agreeTerms ? Colors.green[600] : Colors.grey[400], + ), + onTap: () { + onSelected(!_agreeTerms); + }, + ), + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Text( + TranslationBase.of(context).pharmacyServiceTermsCondition, + style: TextStyle(height: 1, fontWeight: FontWeight.normal, fontSize: 13), + ), + )), + InkWell( + child: Icon( + Icons.info, + size: 20, + color: Colors.grey[600], + ), + onTap: () { + onInfoClick(); + }, + ), + ], + ), + ); +} + +Widget _payNow(BuildContext context, {@required VoidCallback onPayNowClick}) { + bool isPayNowAQctive = (_agreeTerms && (_selectedPaymentMethod != null)); + + return Padding( + padding: const EdgeInsets.all(5), + child: Container( + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Padding( + padding: const EdgeInsets.all(5), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text('${TranslationBase.of(context).subtotal}: ${'999.9'} ${TranslationBase.of(context).sar}', + style: TextStyle(height: 1.5, fontWeight: FontWeight.bold, color: Colors.grey, fontSize: 8)), + Text('${TranslationBase.of(context).vat}: ${'14.9'} ${TranslationBase.of(context).sar}', style: TextStyle(height: 1.5, fontWeight: FontWeight.bold, color: Colors.grey, fontSize: 8)), + Padding( + padding: const EdgeInsets.all(3), + child: Container( + height: 0.25, + width: 120, + color: Colors.grey[300], + ), + ), + Text(' ${TranslationBase.of(context).total}: 999.99 ${TranslationBase.of(context).sar}', + style: TextStyle(height: 1.5, fontWeight: FontWeight.bold, color: Colors.black54, fontSize: 15)) + ], + ), + ), + Expanded(child: Container()), + RaisedButton( + child: Text( + TranslationBase.of(context).payNow, + 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: isPayNowAQctive ? onPayNowClick : null, + ), + ], + )), + ); +} +// ------------------- + +Widget _cartItemDeleteContainer() { + _animationController.duration = Duration(milliseconds: 500); + _animationController.repeat(reverse: true); + return FadeTransition( + opacity: _animationController, + child: Padding( + padding: const EdgeInsets.all(5), + child: Container( + decoration: BoxDecoration( + color: Colors.red, + boxShadow: [ + BoxShadow( + color: Colors.grey[500], + blurRadius: 2, + spreadRadius: 1, + ), + ], + borderRadius: BorderRadius.all(Radius.circular(5)), + ), + child: Center( + child: Text( + "Deleting...", + style: TextStyle( + fontWeight: FontWeight.normal, + fontSize: 15, + color: Colors.white, + ), + )), + ), + ), + ); +} diff --git a/lib/pages/packages_offers/OfferAndPackagesPage.dart b/lib/pages/packages_offers/OfferAndPackagesPage.dart new file mode 100644 index 00000000..0a83c683 --- /dev/null +++ b/lib/pages/packages_offers/OfferAndPackagesPage.dart @@ -0,0 +1,416 @@ +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/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/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/Loader/gif_loader_container.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; + +class PackagesHomePage extends StatefulWidget { + dynamic offersModel; + PackagesHomePage({@required this.offersModel}); + + @override + _PackagesHomePageState createState() => _PackagesHomePageState(); + +} + +class _PackagesHomePageState extends State with AfterLayoutMixin{ + getLanguageID() async { + languageID = await sharedPref.getString(APP_LANGUAGE); + } + + @override + void initState() { + super.initState(); + getLanguageID(); + } + + @override + void afterFirstLayout(BuildContext context) async{ + viewModel.service.loadOffersPackagesDataForMainPage(context: context, completion: (){ + setState((){}); + }); + } + + // Controllers + var _searchTextController = TextEditingController(); + var _filterTextController = TextEditingController(); + var _carouselController = CarouselController(); + + + int carouselIndicatorIndex = 0; + CarouselSlider _bannerCarousel; + TextField _textFieldSearch; + TextField _textFieldFilterSelection; + + ListView _listViewLatestOffers; + ListView _listViewBestSeller; + + PackagesViewModel viewModel; + + onCartClick(){ + if (viewModel.service.customer == null){ + utils.Utils.showErrorToast("Cart is empty for your current session"); + return; + } + Navigator.of(context).push( + MaterialPageRoute( + builder: (BuildContext context) => PackagesCartPage() + ) + ); + } + + onProductCartClick(PackagesResponseModel product) async { + if(viewModel.service.customer == null) + await viewModel.service.createCustomer(PackagesCustomerRequestModel(email: "zikambrani@gmail.com", phoneNumber: "0500409598"), context: context); + + 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) { + utils.Utils.showErrorToast(error); + }); + } + } + + @override + Widget build(BuildContext context) { + + return BaseView( + 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); + }), + ), + + 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); + } + ); + } + + + + + showClinicSelectionList() async { + var clinics = viewModel.service.categoryList; + if(clinics.isEmpty) { + GifLoaderDialogUtils.showMyDialog(context); + clinics = await viewModel.service.getAllCategories(OffersCategoriesRequestModel()); + GifLoaderDialogUtils.hideDialog(context); + } + + List options = clinics.map((e) => e.toString()).toList(); + + showMaterialSelectionPicker( + context: context, + title: "Select Clinic", + items: options, + selectedItem: options.first, + onChanged: (value) async { + var selectedClinic = clinics.firstWhere((element) => element.toString() == value); + var clinicProducts = await viewModel.service.getAllProducts(request: OffersProductsRequestModel(categoryId: selectedClinic.id), context: context, showLoading: true); + if(clinicProducts.isNotEmpty) + Navigator.of(context).push( + MaterialPageRoute( + builder: (BuildContext context) => ClinicPackagesPage(products: clinicProducts) + ) + ); + else + utils.Utils.showErrorToast("No offers available for this clinic"); + }, + ); + } + + //---------------------------------- + // Main Widgets of Page + //---------------------------------- + + CarouselSlider bannerCarousel(){ + _bannerCarousel = CarouselSlider.builder( + carouselController: _carouselController, + itemCount: 10, + itemBuilder: (BuildContext context, int itemIndex) { + return Padding( + padding: const EdgeInsets.only(top: 10, bottom: 10, left: 15, right: 15), + child: FractionallySizedBox( + widthFactor: 1, + heightFactor: 1, + child: utils.applyShadow( + spreadRadius: 1, + blurRadius: 5, + child: InkWell( + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: utils.Utils.loadNetworkImage(url: "https://wallpaperaccess.com/full/30103.jpg",) + ), + onTap: (){ + Navigator.of(context).push( + MaterialPageRoute( + builder: (BuildContext context) => OfferAndPackagesDetail(model: "",) + ) + ); + }, + ) + ), + ), + ); + }, + options: CarouselOptions( + autoPlayInterval: Duration(milliseconds: 3500), + enlargeStrategy: CenterPageEnlargeStrategy.scale, + enlargeCenterPage: true, + autoPlay: false, + autoPlayCurve: Curves.fastOutSlowIn, + enableInfiniteScroll: true, + autoPlayAnimationDuration: Duration(milliseconds: 1500), + viewportFraction: 1, + onPageChanged: (page, reason){ + setState(() { + carouselIndicatorIndex = page; + }); + }, + ), + ); + return _bannerCarousel; + } + + TextField searchTextField(){ + return _textFieldSearch = + TextField( + controller: _searchTextController, + decoration: InputDecoration( + contentPadding: EdgeInsets.only(top: 0.0, bottom: 0.0, left: 10, right: 10), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( width: 0.5, color: Colors.grey), + borderRadius: const BorderRadius.all( + const Radius.circular(10.0), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( width: 1, color: Colors.grey), + borderRadius: const BorderRadius.all( + const Radius.circular(10.0), + ), + ), + filled: true, + fillColor: Colors.white, + hintText: "Search", + hintStyle: TextStyle(color: Colors.grey[350], fontWeight: FontWeight.bold), + suffixIcon: IconButton( + onPressed: (){ + // viewModel.search(text: _searchTextController.text); + }, + icon: Icon(Icons.search_rounded, size: 35,), + ), + ), + ); + + } + + Widget filterOptionSelection(){ + _textFieldFilterSelection = + TextField( + enabled: false, + controller: _searchTextController, + decoration: InputDecoration( + contentPadding: EdgeInsets.only(top: 0.0, bottom: 0.0, left: 10, right: 10), + border: OutlineInputBorder( + borderSide: BorderSide(color: Colors.grey, width: 1), + borderRadius: const BorderRadius.all( + const Radius.circular(10.0), + ), + ), + disabledBorder: OutlineInputBorder( + borderSide: BorderSide( width: 0.5, color: Colors.grey), + borderRadius: const BorderRadius.all( + const Radius.circular(10.0), + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: const BorderRadius.all( + const Radius.circular(10.0), + ), + ), + filled: true, + fillColor: Colors.white, + hintText: "Browse offers by Clinic", + hintStyle: TextStyle(color: Colors.grey[350], fontWeight: FontWeight.bold), + suffixIcon: IconButton( + onPressed: (){ + showClinicSelectionList(); + }, + icon: Icon(Icons.keyboard_arrow_down_rounded, size: 35, color: Colors.grey,), + ), + ), + ); + + return InkWell( + child: _textFieldFilterSelection, + onTap: (){ + showClinicSelectionList(); + }, + ); + + } + + Widget latestOfferListView({@required double itemWidth, @required double itemContentPadding}){ + return _listViewLatestOffers = + ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: viewModel.bestSellerList.length, + itemBuilder: (BuildContext context, int index) { + return PackagesItemCard(itemWidth: itemWidth, itemContentPadding: itemContentPadding, itemModel: viewModel.bestSellerList[index], onCartClick: onProductCartClick,); + }, + separatorBuilder: separator, + ); + + } + + Widget bestSellerListView({@required double itemWidth, @required double itemContentPadding}){ + return _listViewLatestOffers = + ListView.separated( + scrollDirection: Axis.horizontal, + itemCount: viewModel.bestSellerList.length, + itemBuilder: (BuildContext context, int index) { + return PackagesItemCard(itemWidth: itemWidth, itemContentPadding: itemContentPadding, itemModel: viewModel.bestSellerList[index], onCartClick: onProductCartClick,); + }, + separatorBuilder: separator, + ); + + } + + + Widget separator(BuildContext context, int index){ + return Container( + width: 1, + decoration: BoxDecoration( + gradient: LinearGradient( + begin: Alignment(-1.0, -2.0), + end: Alignment(1.0, 4.0), + colors: [ + Colors.grey, + Colors.grey[100], + Colors.grey[200], + Colors.grey[300], + Colors.grey[400], + Colors.grey[500] + ] + )), + ); + } +} diff --git a/lib/routes.dart b/lib/routes.dart index b11025c2..57452796 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -10,6 +10,8 @@ import 'package:diplomaticquarterapp/pages/login/welcome.dart'; import 'package:diplomaticquarterapp/pages/login/login-type.dart'; 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/settings/settings.dart'; import 'package:diplomaticquarterapp/pages/symptom-checker/info.dart'; import 'package:diplomaticquarterapp/pages/symptom-checker/select-gender.dart'; @@ -35,6 +37,9 @@ const String SYMPTOM_CHECKER = 'symptom-checker'; const String SYMPTOM_CHECKER_INFO = 'symptom-checker-info'; const String SELECT_GENDER = 'select-gender'; const String SETTINGS = 'settings'; +const String PACKAGES_OFFERS = 'packages-offers'; +const String PACKAGES_OFFERS_CART = 'packages-offers-cart'; + var routes = { SPLASH: (_) => SplashScreen(), HOME: (_) => LandingPage(), @@ -52,5 +57,7 @@ var routes = { SYMPTOM_CHECKER: (_) => SymptomChecker(), SYMPTOM_CHECKER_INFO: (_) => SymptomInfo(), SELECT_GENDER: (_) => SelectGender(), - SETTINGS: (_) => Settings() + SETTINGS: (_) => Settings(), + PACKAGES_OFFERS: (_) => PackagesHomePage(), + PACKAGES_OFFERS_CART: (_) => PackagesCartPage(), }; diff --git a/lib/uitl/gif_loader_dialog_utils.dart b/lib/uitl/gif_loader_dialog_utils.dart index ac37cdfb..785a6c6c 100644 --- a/lib/uitl/gif_loader_dialog_utils.dart +++ b/lib/uitl/gif_loader_dialog_utils.dart @@ -8,6 +8,10 @@ class GifLoaderDialogUtils { } static hideDialog(BuildContext context) { - Navigator.of(context).pop(); + try{ + Navigator.of(context).pop(); + }catch(error){ + Future.delayed(Duration(milliseconds: 250)).then((value) => Navigator.of(context).pop()); + } } } diff --git a/lib/uitl/translations_delegate_base.dart b/lib/uitl/translations_delegate_base.dart index 9ed7b478..97399f31 100644 --- a/lib/uitl/translations_delegate_base.dart +++ b/lib/uitl/translations_delegate_base.dart @@ -1110,6 +1110,11 @@ class TranslationBase { String get submitncontinue => localizedValues["submitncontinue"][locale.languageCode]; String get areyousure => localizedValues["areyousure"][locale.languageCode]; String get preferredunit => localizedValues["preferredunit"][locale.languageCode]; + + + // Offer And Packahes + String get subT=> localizedValues['OffersAndPackages'][locale.languageCode]; + String get totalWithColonRight => localizedValues['totalWithColonRight'][locale.languageCode]; } class TranslationBaseDelegate extends LocalizationsDelegate { diff --git a/lib/uitl/utils.dart b/lib/uitl/utils.dart index 85e97429..4a7eaead 100644 --- a/lib/uitl/utils.dart +++ b/lib/uitl/utils.dart @@ -3,6 +3,7 @@ import 'dart:core'; import 'dart:typed_data'; import 'package:badges/badges.dart'; +import 'package:cached_network_image/cached_network_image.dart'; import 'package:connectivity/connectivity.dart'; import 'package:diplomaticquarterapp/config/shared_pref_kay.dart'; import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; @@ -35,7 +36,6 @@ import 'package:diplomaticquarterapp/widgets/dialogs/alert_dialog.dart'; import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:shared_preferences/shared_preferences.dart'; import '../Constants.dart'; import 'app_shared_preferences.dart'; @@ -534,8 +534,44 @@ class Utils { return medical; } + + static Widget loadNetworkImage({@required String url, BoxFit fitting = BoxFit.cover}){ + return CachedNetworkImage( + placeholderFadeInDuration: Duration(milliseconds: 250), + fit: fitting, + imageUrl: url, + placeholder: (context, url) => Container( + child: Center( + child: CircularProgressIndicator() + ) + ), + errorWidget: (context, url, error){ + return Icon(Icons.error, color: Colors.red, size: 50,); + } + ); + } } + + + +Widget applyShadow({ Color color = Colors.grey, double shadowOpacity = 0.5, double spreadRadius = 2, double blurRadius = 7, Offset offset = const Offset(2, 2), @required Widget child}){ + return Container( + decoration: BoxDecoration( + boxShadow: [ + BoxShadow( + color: color.withOpacity(shadowOpacity), + spreadRadius: spreadRadius, + blurRadius: blurRadius, + offset: offset, // changes position of shadow + ), + ], + ), + child: child, + ); +} + + Future userData() async { var userData = AuthenticatedUser.fromJson(await AppSharedPreferences().getObject(MAIN_USER)); return userData; diff --git a/lib/widgets/CounterView.dart b/lib/widgets/CounterView.dart new file mode 100644 index 00000000..6ba77c15 --- /dev/null +++ b/lib/widgets/CounterView.dart @@ -0,0 +1,188 @@ +import 'package:flutter/material.dart'; + +typedef StepperCallbackFuture = Future Function(int apply, int total); + +class StepperView extends StatefulWidget { + final double height; + final Color foregroundColor; + final Color backgroundColor; + final double buttonPadding; + + final int initialNumber; + final int maxNumber; + final int minNumber; + final StepperCallbackFuture counterCallback; + final Function increaseCallback; + final Function decreaseCallback; + + StepperView({this.initialNumber = 1, this.minNumber = 1, this.maxNumber, @required this.counterCallback, this.increaseCallback, this.decreaseCallback, this.height = 25, @required this.foregroundColor, @required this.backgroundColor, this.buttonPadding = 1}){ + assert((this.initialNumber >= this.minNumber && this.initialNumber <= this.maxNumber)); + } + @override + _StepperViewState createState() => _StepperViewState(); +} + +class _StepperViewState extends State { + int _currentCount; + StepperCallbackFuture _counterCallback; + Function _increaseCallback; + Function _decreaseCallback; + + @override + void initState() { + _currentCount = widget.initialNumber ?? 1; + _counterCallback = widget.counterCallback; + _increaseCallback = widget.increaseCallback ?? () {}; + _decreaseCallback = widget.decreaseCallback ?? () {}; + super.initState(); + } + + bool loadingInc = false; + bool loadingDec = false; + + @override + Widget build(BuildContext context) { + return Container( + padding: EdgeInsets.all(widget.buttonPadding), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular((widget.height/2) + (widget.buttonPadding*2)), + color: widget.backgroundColor, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + _createDecrementButton( + (_currentCount > widget.minNumber) ? () => _decrement() : null, + ), + Container( + width: 25, + child: Center( + child: Text( + _currentCount.toString(), + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.normal, + height: 1.5, + color: Colors.black, + ) + ), + ) + ), + _createIncrementButton( + (_currentCount < widget.maxNumber) ? () => _increment() : null + ), + ], + ), + ); + } + + void _increment() async{ + doInc({@required bool can}){ + if(can) + setState(() { + _currentCount++; + _increaseCallback(); + }); + } + + if (_currentCount < widget.maxNumber){ + if(_counterCallback == null) + doInc(can: true); + else { + setState(() => loadingInc = true); + var result = (await _counterCallback(1,_currentCount)); + doInc(can: result); + setState(() => loadingInc = false); + } + } + } + + void _decrement() async{ + doDec({@required bool can}){ + if(can) + setState(() { + _currentCount--; + _decreaseCallback(); + }); + } + if (_currentCount > widget.minNumber) { + if(_counterCallback == null) + doDec(can: true); + else { + setState(() => loadingDec = true); + var result = (await _counterCallback(-1,_currentCount)); + doDec(can: result); + setState(() => loadingDec = false); + } + } + } + + Widget _createIncrementButton(Function onPressed,) { + return Stack( + children: [ + RawMaterialButton( + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + constraints: BoxConstraints(minWidth: widget.height, minHeight: widget.height), + onPressed: onPressed, + elevation: 2.0, + fillColor: widget.foregroundColor, + child: + Icon( + Icons.add, + color: (_currentCount < widget.maxNumber) ? Colors.grey[700] : Colors.grey[400], + size: 12.0, + ), + shape: CircleBorder(), + ), + + if(loadingInc) + Container( + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.8), + borderRadius: BorderRadius.circular(widget.height/2), + ), + height: widget.height, + width: widget.height, + child: CircularProgressIndicator( + strokeWidth: 3, + valueColor: AlwaysStoppedAnimation(Colors.green) + ) + ) + ], + ); + } + + Widget _createDecrementButton(Function onPressed) { + return Stack( + children: [ + RawMaterialButton( + materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, + constraints: BoxConstraints(minWidth: widget.height, minHeight: widget.height), + onPressed: onPressed, + elevation: 2.0, + fillColor: widget.foregroundColor, + child: Icon( + Icons.remove, + color: (_currentCount > widget.minNumber) ? Colors.grey[700] : Colors.grey[400], + size: 12.0, + ), + shape: CircleBorder(), + ), + + if(loadingDec) + Container( + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.8), + borderRadius: BorderRadius.circular(widget.height/2), + ), + height: widget.height, + width: widget.height, + child: CircularProgressIndicator( + strokeWidth: 3, + valueColor: AlwaysStoppedAnimation(Colors.red) + ) + ) + ], + ); + } +} diff --git a/lib/widgets/carousel_indicator/carousel_indicator.dart b/lib/widgets/carousel_indicator/carousel_indicator.dart new file mode 100644 index 00000000..020c44d8 --- /dev/null +++ b/lib/widgets/carousel_indicator/carousel_indicator.dart @@ -0,0 +1,197 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + + +class CarouselIndicator extends StatefulWidget { + /// width of the indicator + final double width; + + /// height of the indicator + final double height; + + /// space between indicators. + final double space; + + /// count of indicator + final int count; + + /// active color + final Color activeColor; + + /// normal color + final Color color; + + /// use this to give some radius to the corner indicator + final double cornerRadius; + + /// duration for slide animation + final int animationDuration; + + final int index; + + final Function(int index) onClick; + + CarouselIndicator({ + Key key, + this.width: 20.0, + this.height: 6, + this.space: 5.0, + this.count, + this.cornerRadius: 6, + this.animationDuration: 300, + this.color: Colors.white30, + this.index, + this.activeColor: Colors.white, + this.onClick + }) : assert(count != null && count != 0), + assert(index != null && index >= 0), + super(key: key); + + @override + State createState() { + return new _CarouselIndicatorState(); + } +} + +class _CarouselIndicatorState extends State + with TickerProviderStateMixin { + /// [Tween] object of type double + Tween _tween; + + /// [AnimationController] object + AnimationController _animationController; + + /// [Aniamtion] object + Animation _animation; + + /// [Paint] object to paint our indicator + Paint _paint = new Paint(); + + /// Method to initilize [BasePainter] to paint indicators. + BasePainter _createPainer() { + return SlidePainter(widget, _animation.value, _paint); + } + + @override + Widget build(BuildContext context) { + Widget child = new SizedBox( + width: widget.count * widget.width + (widget.count - 1) * widget.space, + height: widget.height, + child: CustomPaint( + painter: _createPainer(), + ), + ); + + return InkWell( + child: child, + onTap: (){ + if(widget.onClick != null) + widget.onClick(0); + }, + ); + } + + @override + void initState() { + /// for initial index=0 we do not want to change any value so setting [_tween] to (0.0,0.0), + createAnimation(0.0, 0.0); + super.initState(); + } + + @override + void didUpdateWidget(CarouselIndicator oldWidget) { + if (widget.index != oldWidget.index) { + if (widget.index != 0) { + _animationController.reset(); + + /// for each new index we want to change value so setting [_tween] to (oldWidget.index,widget.index) so animation tween from old position to new position rather not start from 0.0 again and again. + createAnimation(oldWidget.index.toDouble(), widget.index.toDouble()); + _animationController.forward(); + } else { + _animationController.reset(); + createAnimation(oldWidget.index.toDouble(), 0.0); + _animationController.forward(); + } + } + super.didUpdateWidget(oldWidget); + } + + @override + void dispose() { + _animationController.dispose(); + super.dispose(); + } + + void createAnimation(double begin, double end) { + _tween = Tween(begin: begin, end: end); + _animationController = AnimationController( + vsync: this, + duration: Duration(milliseconds: widget.animationDuration)); + _animation = _tween.animate(_animationController) + ..addListener(() { + setState(() {}); + }); + } +} + + +/// Base Painter class to draw indicator +abstract class BasePainter extends CustomPainter { + final CarouselIndicator widget; + final double page; + final Paint _paint; + + BasePainter(this.widget, this.page, this._paint); + + /// This method will get body to class extending [BasePainter] and this method will draw the sliding indicator which slide over changing index. + void draw(Canvas canvas, double space, double width, double height, + double radius, double cornerRadius); + + @override + void paint(Canvas canvas, Size size) { + _paint.color = widget.color; + double space = widget.space; + double width = widget.width; + double height = widget.height; + double distance = width + space; + double radius = width / 2; + for (int i = 0, c = widget.count; i < c; ++i) { + canvas.drawRRect( + RRect.fromRectAndRadius( + Rect.fromCenter( + center: Offset((i * distance) + radius, radius), + width: width, + height: height), + Radius.circular(widget.cornerRadius)), + _paint); + } + + _paint.color = widget.activeColor; + draw(canvas, space, width, height, radius, widget.cornerRadius); + } + + @override + bool shouldRepaint(BasePainter oldDelegate) { + return oldDelegate.page != page; + } +} + +/// This class we draw the indicator which slides. +class SlidePainter extends BasePainter { + SlidePainter(CarouselIndicator widget, double page, Paint paint) + : super(widget, page, paint); + + @override + void draw(Canvas canvas, double space, double width, double height, + double radius, double cornerRadius) { + canvas.drawRRect( + RRect.fromRectAndRadius( + Rect.fromCenter( + center: Offset(radius + (page * (width + space)), radius), + width: width, + height: height), + Radius.circular(cornerRadius)), + _paint); + } +} + diff --git a/lib/widgets/offers_packages/PackagesCartItemCard.dart b/lib/widgets/offers_packages/PackagesCartItemCard.dart new file mode 100644 index 00000000..72ce7475 --- /dev/null +++ b/lib/widgets/offers_packages/PackagesCartItemCard.dart @@ -0,0 +1,217 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesCartItemsResponseModel.dart'; +import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesResponseModel.dart'; +import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; +import 'package:diplomaticquarterapp/uitl/utils.dart'; +import 'package:diplomaticquarterapp/widgets/CounterView.dart'; +import 'package:diplomaticquarterapp/widgets/others/StarRating.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + + +bool wide = true; + +class PackagesCartItemCard extends StatefulWidget { + final CartProductResponseModel itemModel; + final StepperCallbackFuture shouldStepperChangeApply ; + + const PackagesCartItemCard( + { + @required this.itemModel, + @required this.shouldStepperChangeApply, + Key key}) + : super(key: key); + + @override + State createState() => PackagesCartItemCardState(); +} + +class PackagesCartItemCardState extends State { + + @override + Widget build(BuildContext context) { + + wide = !wide; + return Container( + color: Colors.transparent, + child: Card( + elevation: 3, + shadowColor: Colors.grey[100], + color: Colors.white, + child: Stack( + children: [ + Container( + height: 100, + child: Row( + children: [ + _image(widget.itemModel.product), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + _itemName(widget.itemModel.product.getName()), + Row( + children: [ + _itemPrice(widget.itemModel.product.price, context: context), + _priceSeperator(), + _itemOldPrice(widget.itemModel.product.oldPrice, context: context), + ], + ), + Row( + children: [ + _itemCounter( + widget.itemModel.quantity, + minQuantity: widget.itemModel.product.orderMinimumQuantity, + maxQuantity: widget.itemModel.product.orderMaximumQuantity, + shouldStepperChangeApply: (apply,total) async{ + bool success = await widget.shouldStepperChangeApply(apply,total); + if(success == true) + setState(() => widget.itemModel.quantity = total); + return success; + } + ), + ], + ), + ], + ) + ], + ), + ), + + Positioned( + bottom: 8, + left: 10, + child: Row( + children: [ + _totalPrice((widget.itemModel.product.price * widget.itemModel.quantity), context: context), + _totalLabel(context: context), + ], + ), + ) + ], + ) + ) + ); + } +} + + +// -------------------- +// Product Image +// -------------------- +Widget _image(PackagesResponseModel model) => AspectRatio( + aspectRatio: 1/1, + child: Padding( + padding: const EdgeInsets.all(10), + child: Container( + decoration: BoxDecoration( + border: Border.all(color: Colors.grey[300], width: 0.25), + boxShadow: [ + BoxShadow(color: Colors.grey[200], blurRadius: 2.0, spreadRadius: 1, offset: Offset(1,1.5)) + ], + borderRadius: BorderRadius.circular(8), + color: Colors.white, + shape: BoxShape.rectangle, + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(8), + child: (model.images.isNotEmpty) + ? Utils.loadNetworkImage(url: model.images.first.src, fitting:BoxFit.fill) + : Container(color: Colors.grey[200]) + ), + ), + ), +); + +// -------------------- +// Product Name +// -------------------- +Widget _itemName(String name) => Padding( + padding: const EdgeInsets.all(0), + child: Text( + name, + style: TextStyle( + fontWeight: FontWeight.normal, + color: Colors.black, + fontSize: 15)) +); + + +Widget _itemPrice(double price, {@required BuildContext context}) => Padding( + padding: const EdgeInsets.all(0), + child: Text( + '${price} ${TranslationBase.of(context).sar}', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.green, + fontSize: 15)) +); + + +// -------------------- +// Price Seperator +// -------------------- +Widget _priceSeperator() => Padding( + padding: const EdgeInsets.only(left: 3, right: 3), + child: Container(height: 0.5, width: 5, color: Colors.grey[100],), +); + + +// -------------------- +// Product Price +// -------------------- +Widget _itemOldPrice(double oldPrice, {@required BuildContext context}) => Padding( + padding: const EdgeInsets.all(0), + child: Text( + '${oldPrice} ${TranslationBase.of(context).sar}', + style: TextStyle( + fontWeight: FontWeight.normal, + decoration: TextDecoration.lineThrough, + color: Colors.grey, + fontSize: 10 + ) + ) +); + +// -------------------- +// Product Price +// -------------------- +Widget _itemCounter(int quantity, {int minQuantity, int maxQuantity, StepperCallbackFuture shouldStepperChangeApply}) => Padding( + padding: const EdgeInsets.all(0), + child: StepperView( + height: 25, + backgroundColor: Colors.grey[300], + foregroundColor: Colors.grey[200], + initialNumber: quantity, + minNumber: minQuantity, + maxNumber: maxQuantity, + counterCallback: shouldStepperChangeApply, + decreaseCallback: (){}, + increaseCallback: (){}, + ) +); + + +Widget _totalLabel({@required BuildContext context}) => Padding( + padding: const EdgeInsets.all(0), + child: Text( + '${TranslationBase.of(context).totalWithColonRight}', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.grey[600], + fontSize: 13 + ) + ) +); + + +Widget _totalPrice(double totalPrice, {@required BuildContext context}) => Padding( + padding: const EdgeInsets.all(0), + child: Text( + '${totalPrice.toStringAsFixed(2)} ${TranslationBase.of(context).sar}', + style: TextStyle( + fontWeight: FontWeight.normal, + color: Colors.green, + fontSize: 12)) +); + diff --git a/lib/widgets/offers_packages/PackagesOfferCard.dart b/lib/widgets/offers_packages/PackagesOfferCard.dart new file mode 100644 index 00000000..af0341c5 --- /dev/null +++ b/lib/widgets/offers_packages/PackagesOfferCard.dart @@ -0,0 +1,157 @@ +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:diplomaticquarterapp/core/model/packages_offers/responses/PackagesResponseModel.dart'; +import 'package:diplomaticquarterapp/uitl/utils.dart'; +import 'package:diplomaticquarterapp/widgets/others/StarRating.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + + +bool wide = true; + +class PackagesItemCard extends StatefulWidget { + final double itemWidth; + final double itemHeight; + final double itemContentPadding; + final PackagesResponseModel itemModel; + final Function(PackagesResponseModel product) onCartClick; + + const PackagesItemCard( + { + this.itemWidth, + this.itemHeight, + @required this.itemModel, + @required this.itemContentPadding, + @required this.onCartClick, + Key key}) + : super(key: key); + + @override + State createState() => PackagesItemCardState(); +} + +class PackagesItemCardState extends State { + + @override + Widget build(BuildContext context) { + wide = !wide; + return Directionality( + textDirection: TextDirection.rtl, + child: Stack( + children: [ + Padding( + padding: EdgeInsets.only( + left: widget.itemContentPadding, + right: widget.itemContentPadding, + top: widget.itemContentPadding + 5), + child: Container( + width: widget.itemWidth, + color: Colors.transparent, + child: Stack( + children: [ + Column( + mainAxisSize: MainAxisSize.max, + children: [ + AspectRatio( + aspectRatio:1 / 1, + child: applyShadow( + child: ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Utils.loadNetworkImage( + url: + "https://wallpaperaccess.com/full/30103.jpg", + )), + )), + Text( + widget.itemModel.getName(), + style: TextStyle( + fontWeight: FontWeight.normal, + color: Colors.black, + fontSize: 15)), + Padding( + padding: const EdgeInsets.only(left: 10, right: 10), + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + mainAxisSize: MainAxisSize.max, + children: [ + Stack( + children: [ + Text( + '${widget.itemModel.oldPrice} ${'SAR'}', + style: TextStyle( + fontWeight: FontWeight.normal, + decoration: TextDecoration.lineThrough, + color: Colors.grey, + fontSize: 12)), + Padding( + padding: const EdgeInsets.only(top: 8), + child: Text( + '${widget.itemModel.price} ${'SAR'}', + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.green, + fontSize: 18)), + ), + Padding( + padding: const EdgeInsets.only(top: 35), + child: StarRating( + size: 15, + totalCount: null, + totalAverage: widget.itemModel.approvedRatingSum.toDouble(), + forceStars: true), + ) + ], + ), + Spacer( + flex: 1, + ), + InkWell( + child: Icon( + Icons.add_shopping_cart_rounded, + size: 30.0, + color: Colors.grey, + ), + onTap: () { + widget.onCartClick(widget.itemModel); + }, + ), + ], + ), + ), + ], + ), + ], + ), + ), + ), + Positioned( + top: 0, + right: 0, + child: Visibility( + visible: false, + child: InkWell( + child: Icon( + Icons.favorite, + size: 40.0, + color: Colors.red, + ), + onTap: () { + + }, + ), + ), + ), + + Positioned( + top: 7, + left: 2, + child: Image.asset( + 'assets/images/discount_${'en'}.png', + height: 60, + width: 60, + ), + ), + ], + ), + ); + } +} diff --git a/lib/widgets/offers_packages/offers_packages.dart b/lib/widgets/offers_packages/offers_packages.dart index 6834d516..8fae69b4 100644 --- a/lib/widgets/offers_packages/offers_packages.dart +++ b/lib/widgets/offers_packages/offers_packages.dart @@ -1,6 +1,5 @@ import 'dart:developer'; -import 'package:carousel_pro/carousel_pro.dart'; import 'package:carousel_slider/carousel_slider.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/requests/OffersCategoriesRequestModel.dart'; import 'package:diplomaticquarterapp/core/model/packages_offers/requests/OffersProductsRequestModel.dart'; diff --git a/lib/widgets/others/StarRating.dart b/lib/widgets/others/StarRating.dart index 2eaa7f91..5620b21a 100644 --- a/lib/widgets/others/StarRating.dart +++ b/lib/widgets/others/StarRating.dart @@ -14,26 +14,26 @@ class StarRating extends StatelessWidget { @override Widget build(BuildContext context) { return Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - if (!forceStars && (totalAverage==null || totalAverage==0)) - Texts("New", style: "caption"), - if (forceStars || (totalAverage!=null && totalAverage>0)) - ...List.generate(5, (index) => - Padding( - padding: EdgeInsets.only(right: 1.0), - child: Icon( - (index+1) <= (totalAverage ?? 0) ? EvaIcons.star : EvaIcons.starOutline, - size: size, - color: (index+1) <= (totalAverage ?? 0) ? Color.fromRGBO(255, 186, 0, 1.0) : Theme.of(context).hintColor + mainAxisAlignment: MainAxisAlignment.start, + children: [ + if (!forceStars && (totalAverage==null || totalAverage==0)) + Texts("New", style: "caption"), + if (forceStars || (totalAverage!=null && totalAverage>0)) + ...List.generate(5, (index) => + Padding( + padding: EdgeInsets.only(right: 1.0), + child: Icon( + (index+1) <= (totalAverage ?? 0) ? EvaIcons.star : EvaIcons.starOutline, + size: size, + color: (index+1) <= (totalAverage ?? 0) ? Color.fromRGBO(255, 186, 0, 1.0) : Theme.of(context).hintColor + ), + ) ), - ) - ), - if (totalCount!=null) - SizedBox(width: 9.0), - if (totalCount!=null) - Texts("("+totalCount.toString()+")", style: "overline", color: Colors.grey[400],) - ] + if (totalCount!=null) + SizedBox(width: 9.0), + if (totalCount!=null) + Texts("("+totalCount.toString()+")", style: "overline", color: Colors.grey[400],) + ] ); } } \ No newline at end of file diff --git a/lib/widgets/others/app_scaffold_widget.dart b/lib/widgets/others/app_scaffold_widget.dart index ca91efe2..af61052e 100644 --- a/lib/widgets/others/app_scaffold_widget.dart +++ b/lib/widgets/others/app_scaffold_widget.dart @@ -27,6 +27,8 @@ import 'arrow_back.dart'; import 'network_base_view.dart'; import 'not_auh_page.dart'; +VoidCallback _onCartClick; + class AppScaffold extends StatelessWidget { final String appBarTitle; final Widget body; @@ -38,7 +40,9 @@ class AppScaffold extends StatelessWidget { final bool isBottomBar; final Widget floatingActionButton; final bool isPharmacy; + final bool isOfferPackages; final bool showPharmacyCart; + final bool showOfferPackagesCart; final String title; final String description; final bool isShowDecPage; @@ -63,6 +67,8 @@ class AppScaffold extends StatelessWidget { this.floatingActionButton, this.isPharmacy = false, this.showPharmacyCart = true, + this.isOfferPackages = false, + this.showOfferPackagesCart = false, this.title, this.description, this.isShowDecPage = true, @@ -74,6 +80,11 @@ class AppScaffold extends StatelessWidget { this.infoList, this.imagesInfo}); + AppScaffold setOnAppBarCartClick(VoidCallback onClick){ + _onCartClick = onClick; + return this; + } + @override Widget build(BuildContext context) { AppGlobal.context = context; @@ -87,6 +98,8 @@ class AppScaffold extends StatelessWidget { showHomeAppBarIcon: showHomeAppBarIcon, isPharmacy: isPharmacy, showPharmacyCart: showPharmacyCart, + isOfferPackages: isOfferPackages, + showOfferPackagesCart: showOfferPackagesCart, isShowDecPage: isShowDecPage, ) : null, @@ -122,7 +135,9 @@ class AppBarWidget extends StatelessWidget with PreferredSizeWidget { final bool showHomeAppBarIcon; final List appBarIcons; final bool isPharmacy; + final bool isOfferPackages; final bool showPharmacyCart; + final bool showOfferPackagesCart; final bool isShowDecPage; AppBarWidget( @@ -131,6 +146,8 @@ class AppBarWidget extends StatelessWidget with PreferredSizeWidget { this.appBarIcons, this.isPharmacy = true, this.showPharmacyCart = true, + this.isOfferPackages = false, + this.showOfferPackagesCart = false, this.isShowDecPage = true}); @override @@ -164,12 +181,25 @@ class AppBarWidget extends StatelessWidget with PreferredSizeWidget { actions: [ (isPharmacy && showPharmacyCart) ? IconButton( - icon: Icon(Icons.shopping_cart), - color: Colors.white, - onPressed: () { - Navigator.of(context).popUntil(ModalRoute.withName('/')); - }) + icon: Icon(Icons.shopping_cart), + color: Colors.white, + onPressed: () { + Navigator.of(context).popUntil(ModalRoute.withName('/')); + }) : Container(), + + (isOfferPackages && showOfferPackagesCart) + ? IconButton( + icon: Icon(Icons.shopping_cart), + color: Colors.white, + onPressed: () { + // Cart Click Event + if(_onCartClick != null) + _onCartClick(); + + }) + : Container(), + if (showHomeAppBarIcon) IconButton( icon: Icon(FontAwesomeIcons.home), @@ -179,6 +209,10 @@ class AppBarWidget extends StatelessWidget with PreferredSizeWidget { context, MaterialPageRoute(builder: (context) => LandingPage()), (Route r) => false); + + // Cart Click Event + if(_onCartClick != null) + _onCartClick(); }, ), if (appBarIcons != null) ...appBarIcons diff --git a/pubspec.yaml b/pubspec.yaml index 3b44f01f..54d08a71 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -101,9 +101,6 @@ dependencies: # Location Helper map_launcher: ^0.8.1 - #carousel slider - carousel_slider: ^2.3.1 - #Calendar Events manage_calendar_events: ^1.0.2 @@ -170,6 +167,10 @@ dependencies: # Dep by Zohaib shimmer: ^1.1.2 + cached_network_image: ^2.5.0 + carousel_slider: ^2.3.1 + flutter_material_pickers: 1.7.4 + flutter_staggered_grid_view: 0.3.4 # Marker Animation flutter_animarker: ^1.0.0 From e0ebb922ed4ebc5d759b2813822935642e316ba1 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 11 Mar 2021 10:55:30 +0300 Subject: [PATCH 07/26] pharmacy fixes --- GoogleService-Info_DQ.plist | 36 +++++++++++++++++ GoogleService-Info_HMG.plist | 38 ++++++++++++++++++ assets/images/logo_HMG.png | Bin 0 -> 38890 bytes .../WifiConnect}/GoogleService-Info.plist | 0 key | Bin 0 -> 2051 bytes lib/config/config.dart | 36 ++++++++++------- lib/config/localized_values.dart | 4 ++ lib/core/service/client/base_app_client.dart | 19 +++++++-- .../parmacyModule/order-preview-service.dart | 6 +-- .../parmacyModule/parmacy_module_service.dart | 2 +- .../NewHomeHealthCare/location_page.dart | 1 + lib/pages/landing/landing_page.dart | 14 +++---- .../product_detail_service.dart | 2 +- lib/widgets/drawer/app_drawer_widget.dart | 2 +- 14 files changed, 128 insertions(+), 32 deletions(-) create mode 100644 GoogleService-Info_DQ.plist create mode 100644 GoogleService-Info_HMG.plist create mode 100644 assets/images/logo_HMG.png rename ios/{ => Runner/WifiConnect}/GoogleService-Info.plist (100%) create mode 100644 key diff --git a/GoogleService-Info_DQ.plist b/GoogleService-Info_DQ.plist new file mode 100644 index 00000000..0c093a2a --- /dev/null +++ b/GoogleService-Info_DQ.plist @@ -0,0 +1,36 @@ + + + + + CLIENT_ID + 864393916058-ekeb4s8tgfo58dutv0l54399t7ivr06r.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.864393916058-ekeb4s8tgfo58dutv0l54399t7ivr06r + API_KEY + AIzaSyA_6ayGCk4fly7o7eTVBrj9kuHBYHMAOfs + GCM_SENDER_ID + 864393916058 + PLIST_VERSION + 1 + BUNDLE_ID + com.cloud.diplomaticquarterapp + PROJECT_ID + diplomaticquarter-d2385 + STORAGE_BUCKET + diplomaticquarter-d2385.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:864393916058:ios:13f787bbfe6051f8b97923 + DATABASE_URL + https://diplomaticquarter-d2385.firebaseio.com + + \ No newline at end of file diff --git a/GoogleService-Info_HMG.plist b/GoogleService-Info_HMG.plist new file mode 100644 index 00000000..153aa2c6 --- /dev/null +++ b/GoogleService-Info_HMG.plist @@ -0,0 +1,38 @@ + + + + + CLIENT_ID + 815750722565-da8p56le8bd6apsbm9eft0jjl1rtpgkt.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.815750722565-da8p56le8bd6apsbm9eft0jjl1rtpgkt + ANDROID_CLIENT_ID + 815750722565-m14h8mkosm7cnq6uh6rhqr54dn02d705.apps.googleusercontent.com + API_KEY + AIzaSyDiXnCO00li4V7Ioa2YZ_M4ECxRsu_P9tA + GCM_SENDER_ID + 815750722565 + PLIST_VERSION + 1 + BUNDLE_ID + com.HMG.Smartphone + PROJECT_ID + api-project-815750722565 + STORAGE_BUCKET + api-project-815750722565.appspot.com + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:815750722565:ios:328ec247a81a2ca23c186c + DATABASE_URL + https://api-project-815750722565.firebaseio.com + + \ No newline at end of file diff --git a/assets/images/logo_HMG.png b/assets/images/logo_HMG.png new file mode 100644 index 0000000000000000000000000000000000000000..0d9e4a56026c52e0ca2cf096a4dadcee98c27155 GIT binary patch literal 38890 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

%S1Pd9nP81ZiB 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 Eg3P3x_W%F@ literal 0 HcmV?d00001 diff --git a/ios/GoogleService-Info.plist b/ios/Runner/WifiConnect/GoogleService-Info.plist similarity index 100% rename from ios/GoogleService-Info.plist rename to ios/Runner/WifiConnect/GoogleService-Info.plist diff --git a/key b/key new file mode 100644 index 0000000000000000000000000000000000000000..15b9f5d1307057e4b8e4bcd4381b23424811dac6 GIT binary patch literal 2051 zcmV+e2>kc{?f&fm000620003100031188k$0003(nN@t?000F5FoFd9Fb)O^D+U1s z0V)C!0RaU71cC(UgT>MCv(e@oDfNKKat;@%p4`DkvJuL`PH*E2{RRXpj8X+Vz6u)a zevfZjqLBl;cIY2&J>kVSmOnh85TlNca*tXy=ZzdqZ*Vi#m^yl{Ll6A;Sd={hT?IVR-vm zsFm$Js?Q^dp9o!qSRcSdC^2E_AlP7`-vDF*M#8~os|f9W9B0|TdDv}@ySNta&9Yrn ztMWQJdtXeJsd1 zKq<_)z$Ik+N!g%?b$VpY+coA!nEY&wh_Ohc8}1-jTREU#|5OvLK{({;mDBQeMpig# zTehwn0;k~~hLqrb;vtW@Me}!^uWZOw$iVnMV3srhjO=L)oJUX!(qD1ses|u&Nwioz zj+o`f9ed0UZJG6Ab~*}zEV>~R%-bZlckN2=)AHQqfI9a2&r!4j#F|-{Hey;yL;eas z!}{x-W9p?rgJgllLS=%ZZCI}uwYVNVts-(A;Vri?b2$bR<6+^mo?6~bi<6gK;zdIQ!icx8FBm&qi8FROwQbzQ zw|)D%S6A->!Z!SufL%t0YI;<{3u6GuZg&{;MqWRJ+`evF^h>P(WH3BA23c)%y!|yRfZ5fr(kpW{ zCf1T3e59lbZ_(19wN;BVSk`6GK}L~z=&IqjxqpUB(3%~!t38n%yAnb^KvwxHS|)Z` zmzS*45qo}8{IjS=Wr@;;HP#Ci%UCc)>vb>CL8+e9s1xSeeKD*@>}^Cl1P4wz#3Tn} z|45J2ehH;v4w5vX*?7lVO+z8V0000100mesH842<00O@-f&#lRf&rtT0|Eg80t5r% zH@Pqk1_>&LNQUzjQ&MLzN8IfTy_}v&8I@pw%wKNScy*LA3rc7KjA4 zWfC{O=iO5mqz#*(q&OyMdnNv6mZ@&>3L=UiQdm+;^2KQfDfoF=Djh9`E|#|nE*@Xh z(G2O~7*w_rC*WzLtCZ_O*hL%9*LNl!ullZ1L4!w0-YQ_Zb?SEbCN_?}r-r_nag8Ej zPm?AO0!sn|0RRD`Aut~>9R>qc9S#H*1Qd_SMR1N)p%d$|2yTd-kw{+84ni;u1_>&L zNQU-FMCu!XEeENt zbZYF>l?W5mT{|+Z_k)_(okzb+Ou{tP5Eh&Yha7vf3Zj*o9Y2*$m~-ET@4PCHJr+g= zI;*a_R6jK`yvN45zw?CC)lzz8uUW_?;Xz5T+b8EF9*97}49<0J|DmrGoq;v=4Vw=b zO*`9K?i9?i)Dsf$QBJ(@l{NnX&kh4pp^|M%ab0gp&nG4+V65?Tip%_;*SP45Fj)Xr hRD#uFfsONE{KL;10I7=mQW|g4`W}C56fpelh$yQ4rvv~1 literal 0 HcmV?d00001 diff --git a/lib/config/config.dart b/lib/config/config.dart index d95c2f0a..d28ade4c 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -1,9 +1,7 @@ import 'dart:io'; -import 'package:diplomaticquarterapp/core/service/geofencing/GeofencingServices.dart'; import 'package:diplomaticquarterapp/models/Request.dart'; import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; -import 'package:diplomaticquarterapp/widgets/mobile-no/mobile_no.dart'; const MAX_SMALL_SCREEN = 660; @@ -13,11 +11,16 @@ const PACKAGES_CATEGORIES = '/api/categories'; const PACKAGES_PRODUCTS = '/api/products'; const BASE_URL = 'https://uat.hmgwebservices.com/'; -//const BASE_URL = 'https://.hmgwebservices.com/'; +// const BASE_URL = 'https://hmgwebservices.com/'; + +// Pharmacy UAT URLs +// const BASE_PHARMACY_URL = 'https://uat.hmgwebservices.com/epharmacy/api/'; +// const PHARMACY_BASE_URL = 'https://uat.hmgwebservices.com/epharmacy/api/'; + +// Pharmacy Production URLs +const BASE_PHARMACY_URL = 'https://mdlaboratories.com/exacartapi/api/'; +const PHARMACY_BASE_URL = 'https://mdlaboratories.com/exacartapi/api/'; -//const BASE_PHARMACY_URL = 'http://swd-pharapp-01:7200/api/'; -const BASE_PHARMACY_URL = 'https://uat.hmgwebservices.com/epharmacy/api/'; -const PHARMACY_BASE_URL = 'https://uat.hmgwebservices.com/epharmacy/api/'; const PING_SERVICE = 'Services/Weather.svc/REST/CheckConnectivity'; const GET_PROJECT = 'Services/Lists.svc/REST/GetProject'; @@ -92,9 +95,12 @@ const GET_NEAREST_HOSPITAL = 'Services/Patients.svc/REST/Patient_GetProjectAvgERWaitingTime'; ///ED Online -const ER_GET_VISUAL_TRIAGE_QUESTIONS = "services/Doctors.svc/REST/ER_GetVisualTriageQuestions"; -const ER_SAVE_TRIAGE_INFORMATION = "services/Doctors.svc/REST/ER_SaveTriageInformation"; -const ER_GetPatientPaymentInformationForERClinic = "services/Doctors.svc/REST/ER_GetPatientPaymentInformationForERClinic"; +const ER_GET_VISUAL_TRIAGE_QUESTIONS = + "services/Doctors.svc/REST/ER_GetVisualTriageQuestions"; +const ER_SAVE_TRIAGE_INFORMATION = + "services/Doctors.svc/REST/ER_SaveTriageInformation"; +const ER_GetPatientPaymentInformationForERClinic = + "services/Doctors.svc/REST/ER_GetPatientPaymentInformationForERClinic"; ///Er Nearest const GET_AMBULANCE_REQUEST = @@ -449,7 +455,7 @@ const GET_ANCILLARY_ORDERS = // const GET_WISHLIST = "http://swd-pharapp-01:7200/api/shopping_cart_items/"; // pharmacy -const PHARMACY_AUTORZIE_CUSTOMER = "epharmacy/api/AutorizeCustomer"; +const PHARMACY_AUTORZIE_CUSTOMER = "AutorizeCustomer"; const PHARMACY_VERIFY_CUSTOMER = "VerifyCustomer"; const PHARMACY_GET_COUNTRY = "countries"; const PHARMACY_CREATE_CUSTOMER = "epharmacy/api/CreateCustomer"; @@ -470,9 +476,9 @@ const GET_Cancel_ORDER = "cancelorder/"; const WRITE_REVIEW = "Content-Type" + "text/plain; charset=utf-8"; const GET_SHOPPING_CART = "shopping_cart_items/"; const GET_SHIPPING_OPTIONS = "get_shipping_option/"; -const DELETE_SHOPPING_CART = "epharmacy/api/delete_shopping_cart_items/"; +const DELETE_SHOPPING_CART = "delete_shopping_cart_items/"; const DELETE_SHOPPING_CART_ALL = "delete_shopping_cart_item_by_customer/"; -const ORDER_SHOPPING_CART = "epharmacy/api/orders"; +const ORDER_SHOPPING_CART = "orders"; const GET_LACUM_ACCOUNT_INFORMATION = "Services/Patients.svc/REST/GetLakumAccountInformation"; const GET_LACUM_GROUP_INFORMATION = @@ -529,11 +535,11 @@ const GET_BRAND_ITEMS = "products"; // External API const ADD_ADDRESS_INFO = - "https://mdlaboratories.com/exacartapi/api/addcustomeraddress"; + "addcustomeraddress"; const GET_CUSTOMER_ADDRESSES = - "https://mdlaboratories.com/exacartapi/api/Customers/"; + "Customers/"; const GET_CUSTOMER_INFO = - "https://mdlaboratories.com/exacartapi/api/VerifyCustomer"; + "VerifyCustomer"; //Pharmacy diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index 03891edc..8254daae 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -1966,5 +1966,9 @@ const Map localizedValues = { "errorChiefComplaints": {"en": "Please Chief Complaints", "ar": "يرجى ادخال الشكوى الرئيسة"}, "errorExpectedArrivalTimes": {"en": "Please Expected arrival time", "ar": "يرجى ادخال الوقت المتوقع للوصول"}, "expectedArrivalTime": {"en": "Expected arrival time", "ar": "الوقت المتوقع للوصول"}, + "add-address": { + "en": "Add new address", + "ar": "اضف عنوان جديد" + }, }; diff --git a/lib/core/service/client/base_app_client.dart b/lib/core/service/client/base_app_client.dart index fab6d8fd..f4dc1d78 100644 --- a/lib/core/service/client/base_app_client.dart +++ b/lib/core/service/client/base_app_client.dart @@ -303,7 +303,8 @@ class BaseAppClient { onFailure('Error While Fetching data', statusCode); } } else { - var parsed = json.decode(response.body.toString()); + // var parsed = json.decode(response.body.toString()); + var parsed = json.decode(utf8.decode(response.bodyBytes)); onSuccess(parsed, statusCode); } } else { @@ -400,6 +401,8 @@ class BaseAppClient { Function(String error, int statusCode) onFailure, bool isAllowAny = false, bool isExternal = false}) async { + var token = await sharedPref.getString(PHARMACY_AUTORZIE_TOKEN); + var user = await sharedPref.getObject(USER_PROFILE); String url; if (isExternal) { url = endPoint; @@ -407,8 +410,7 @@ class BaseAppClient { url = BASE_PHARMACY_URL + endPoint; } try { - //Map profile = await sharedPref.getObj(DOCTOR_PROFILE); - if (!isExternal) { + if (isExternal) { String token = await sharedPref.getString(TOKEN); var languageID = await sharedPref.getStringWithDefaultValue(APP_LANGUAGE, 'ar'); @@ -478,16 +480,25 @@ class BaseAppClient { if (await Utils.checkConnection()) { final response = await http.post(url.trim(), body: json.encode(body), headers: { + // 'Content-Type': 'application/json', + // 'Accept': 'application/json', + // 'Statictoken': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9', 'Content-Type': 'application/json', 'Accept': 'application/json', + 'Authorization': token ?? '', + 'Mobilenumber': user != null + ? getPhoneNumberWithoutZero(user['MobileNumber'].toString()) + : "", 'Statictoken': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9', + 'Username': user != null ? user['PatientID'].toString() : "", }); final int statusCode = response.statusCode; print("statusCode :$statusCode"); if (statusCode < 200 || statusCode >= 400 || json == null) { onFailure('Error While Fetching data', statusCode); } else { - var parsed = json.decode(response.body.toString()); + // var parsed = json.decode(response.body.toString()); + var parsed = json.decode(utf8.decode(response.bodyBytes)); if (parsed['Response_Message'] != null) { onSuccess(parsed, statusCode); } else { diff --git a/lib/core/service/parmacyModule/order-preview-service.dart b/lib/core/service/parmacyModule/order-preview-service.dart index 18cfa87e..54dcf7da 100644 --- a/lib/core/service/parmacyModule/order-preview-service.dart +++ b/lib/core/service/parmacyModule/order-preview-service.dart @@ -89,7 +89,7 @@ class OrderPreviewService extends BaseService { Map body = Map(); body["shopping_cart_item"] = choppingCartObject; - await baseAppClient.post("$GET_SHOPPING_CART$productId", + await baseAppClient.pharmacyPost("$GET_SHOPPING_CART$productId", isExternal: false, onSuccess: (response, statusCode) async { localRes = response; }, onFailure: (String error, int statusCode) { @@ -107,7 +107,7 @@ class OrderPreviewService extends BaseService { Map body = Map(); - await baseAppClient.post("$DELETE_SHOPPING_CART$productId", + await baseAppClient.pharmacyPost("$DELETE_SHOPPING_CART$productId", isExternal: false, onSuccess: (response, statusCode) async { localRes = response; }, onFailure: (String error, int statusCode) { @@ -213,7 +213,7 @@ class OrderPreviewService extends BaseService { body['order'] = orderBody; try { - await baseAppClient.post(ORDER_SHOPPING_CART, + await baseAppClient.pharmacyPost(ORDER_SHOPPING_CART, isExternal: false, isAllowAny: true, onSuccess: (response, statusCode) async { }, onFailure: (String error, int statusCode) { hasError = true; diff --git a/lib/core/service/parmacyModule/parmacy_module_service.dart b/lib/core/service/parmacyModule/parmacy_module_service.dart index 9d2b2f6b..7fa095ca 100644 --- a/lib/core/service/parmacyModule/parmacy_module_service.dart +++ b/lib/core/service/parmacyModule/parmacy_module_service.dart @@ -80,7 +80,7 @@ class PharmacyModuleService extends BaseService { }; hasError = false; try { - await baseAppClient.get(PHARMACY_AUTORZIE_CUSTOMER, + await baseAppClient.getPharmacy(PHARMACY_AUTORZIE_CUSTOMER, onSuccess: (dynamic response, int statusCode) async { if (response['Status'] == 200) { await sharedPref.setString( diff --git a/lib/pages/AlHabibMedicalService/HomeHealthCare/NewHomeHealthCare/location_page.dart b/lib/pages/AlHabibMedicalService/HomeHealthCare/NewHomeHealthCare/location_page.dart index 4bf3a762..c9e4262f 100644 --- a/lib/pages/AlHabibMedicalService/HomeHealthCare/NewHomeHealthCare/location_page.dart +++ b/lib/pages/AlHabibMedicalService/HomeHealthCare/NewHomeHealthCare/location_page.dart @@ -49,6 +49,7 @@ class _LocationPageState return BaseView( onModelReady: (model) {}, builder: (_, model, widget) => AppScaffold( + appBarTitle: TranslationBase.of(context).addAddress, isShowDecPage: false, isShowAppBar: true, baseViewModel: model, diff --git a/lib/pages/landing/landing_page.dart b/lib/pages/landing/landing_page.dart index 704aef54..c99930aa 100644 --- a/lib/pages/landing/landing_page.dart +++ b/lib/pages/landing/landing_page.dart @@ -185,7 +185,7 @@ class _LandingPageState extends State with WidgetsBindingObserver { if (results[Permission.camera].isGranted) ; if (results[Permission.photos].isGranted) ; if (results[Permission.accessMediaLocation].isGranted) ; - if (results[Permission.calendar].isGranted) ; + // if (results[Permission.calendar].isGranted) ; }); requestPermissions(); // }); @@ -327,15 +327,15 @@ class _LandingPageState extends State with WidgetsBindingObserver { Permission.photos, Permission.notification, Permission.accessMediaLocation, - Permission.calendar, + // Permission.calendar, Permission.activityRecognition ].request(); - var permissionsGranted = await deviceCalendarPlugin.hasPermissions(); - if (permissionsGranted.isSuccess && !permissionsGranted.data) { - permissionsGranted = await deviceCalendarPlugin.requestPermissions(); - if (!permissionsGranted.isSuccess || !permissionsGranted.data) {} - } + // var permissionsGranted = await deviceCalendarPlugin.hasPermissions(); + // if (permissionsGranted.isSuccess && !permissionsGranted.data) { + // permissionsGranted = await deviceCalendarPlugin.requestPermissions(); + // if (!permissionsGranted.isSuccess || !permissionsGranted.data) {} + // } return permissionResults; } diff --git a/lib/services/pharmacy_services/product_detail_service.dart b/lib/services/pharmacy_services/product_detail_service.dart index 276151a7..f85faf2c 100644 --- a/lib/services/pharmacy_services/product_detail_service.dart +++ b/lib/services/pharmacy_services/product_detail_service.dart @@ -88,7 +88,7 @@ class ProductDetailService extends BaseService { "language_id": 1 } }; - await baseAppClient.pharmacyPost(GET_SHOPPING_CART, + await baseAppClient.pharmacyPost(GET_SHOPPING_CART, isExternal: false, onSuccess: (dynamic response, int statusCode) { _addToCartModel.clear(); response['shopping_carts'].forEach((item) { diff --git a/lib/widgets/drawer/app_drawer_widget.dart b/lib/widgets/drawer/app_drawer_widget.dart index 83b0df5f..841e9f58 100644 --- a/lib/widgets/drawer/app_drawer_widget.dart +++ b/lib/widgets/drawer/app_drawer_widget.dart @@ -81,7 +81,7 @@ class _AppDrawerState extends State { children: [ Container( child: - Image.asset('assets/images/DQ/DQ_logo.png'), + Image.asset('assets/images/logo_HMG.png'), margin: EdgeInsets.all( SizeConfig.imageSizeMultiplier * 4), ), From db0fcd51cc54dfb95b8f9bdc525885b236b03308 Mon Sep 17 00:00:00 2001 From: haroon amjad Date: Thu, 11 Mar 2021 11:30:22 +0300 Subject: [PATCH 08/26] pharmacy updates --- .../pharmacy_module_view_model.dart | 3 ++- lib/widgets/in_app_browser/InAppBrowser.dart | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/core/viewModels/pharmacyModule/pharmacy_module_view_model.dart b/lib/core/viewModels/pharmacyModule/pharmacy_module_view_model.dart index dcf09865..833735bb 100644 --- a/lib/core/viewModels/pharmacyModule/pharmacy_module_view_model.dart +++ b/lib/core/viewModels/pharmacyModule/pharmacy_module_view_model.dart @@ -44,7 +44,8 @@ class PharmacyModuleViewModel extends BaseViewModel { // List get pharmacyPrescriptionsList => PharmacyProduct.pharmacyPrescriptionsList ; Future getPharmacyHomeData() async { - await generatePharmacyToken(); + if(authenticatedUserObject.isLogin) + await generatePharmacyToken(); var data = await sharedPref.getObject(USER_PROFILE); var customerId = await sharedPref.getString(PHARMACY_CUSTOMER_ID); diff --git a/lib/widgets/in_app_browser/InAppBrowser.dart b/lib/widgets/in_app_browser/InAppBrowser.dart index 19da88e7..df535eba 100644 --- a/lib/widgets/in_app_browser/InAppBrowser.dart +++ b/lib/widgets/in_app_browser/InAppBrowser.dart @@ -9,20 +9,23 @@ import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; class MyInAppBrowser extends InAppBrowser { + // static String SERVICE_URL = + // 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx'; // Payfort Payment Gateway URL UAT + static String SERVICE_URL = - 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx'; // Payfort Payment Gateway URL UAT + 'https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx'; //Payfort Payment Gateway URL LIVE - // static String SERVICE_URL = - // 'https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx'; //Payfort Payment Gateway URL LIVE + // static String PREAUTH_SERVICE_URL = + // 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx'; // Payfort PreAuth Payment Gateway URL UAT static String PREAUTH_SERVICE_URL = - 'https://hmgwebservices.com/PayFortWeb/pages/SendPayFortRequest.aspx'; // Payfort PreAuth Payment Gateway URL UAT + 'https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx'; //Payfort PreAuth Payment Gateway URL Live Store - // static String PREAUTH_SERVICE_URL = - // 'https://hmgwebservices.com/PayFortWebLive/pages/SendPayFortRequest.aspx'; //Payfort PreAuth Payment Gateway URL Live Store + // static String PRESCRIPTION_PAYMENT_WITH_ORDERID = + // 'https://uat.hmgwebservices.com/epharmacy/checkout/OpcCompleteRedirectionPaymentClientbyOrder?orderID='; static String PRESCRIPTION_PAYMENT_WITH_ORDERID = - 'https://uat.hmgwebservices.com/epharmacy/checkout/OpcCompleteRedirectionPaymentClientbyOrder?orderID='; + 'https://mdlaboratories.com/exacartapi/checkout/OpcCompleteRedirectionPaymentClientbyOrder?orderID='; //Live static List successURLS = [ 'success', @@ -260,7 +263,6 @@ class MyInAppBrowser extends InAppBrowser { String patientName, dynamic patientID, AuthenticatedUser authUser) async { - String pharmacyURL = PRESCRIPTION_PAYMENT_WITH_ORDERID + order.orderGuid + '&&CustomerId=' + @@ -336,7 +338,6 @@ class MyInAppBrowser extends InAppBrowser { '' + ''; } - } class MyChromeSafariBrowser extends ChromeSafariBrowser { From 66acce3b40fe3d429dd1baf97c67fff8e79ee278 Mon Sep 17 00:00:00 2001 From: Sultan Khan Date: Thu, 11 Mar 2021 11:41:02 +0300 Subject: [PATCH 09/26] ancillary order pages added --- lib/config/config.dart | 7 +- lib/config/localized_values.dart | 14 +- .../service/ancillary_orders_service.dart | 180 +++++++++++++ .../ancillary_orders_view_model.dart | 18 +- lib/locator.dart | 6 +- .../ancillary_order_proc_model.dart | 249 ++++++++++++++++++ .../all_habib_medical_service_page.dart | 3 +- .../ancillary-orders/ancillaryOrders.dart | 148 ++++++++++- .../ancillaryOrdersDetails.dart | 196 ++++++++++++++ lib/uitl/translations_delegate_base.dart | 16 +- .../others/floating_button_search.dart | 21 +- 11 files changed, 836 insertions(+), 22 deletions(-) create mode 100644 lib/models/anicllary-orders/ancillary_order_proc_model.dart create mode 100644 lib/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrdersDetails.dart diff --git a/lib/config/config.dart b/lib/config/config.dart index 4b976928..be71b6aa 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -12,8 +12,8 @@ const EXA_CART_API_BASE_URL = 'https://mdlaboratories.com/exacartapi'; const PACKAGES_CATEGORIES = '/api/categories'; const PACKAGES_PRODUCTS = '/api/products'; -//const BASE_URL = 'https://uat.hmgwebservices.com/'; -const BASE_URL = 'https://hmgwebservices.com/'; +const BASE_URL = 'https://uat.hmgwebservices.com/'; +//const BASE_URL = 'https://hmgwebservices.com/'; //const BASE_PHARMACY_URL = 'http://swd-pharapp-01:7200/api/'; const BASE_PHARMACY_URL = 'https://uat.hmgwebservices.com/epharmacy/api/'; @@ -440,6 +440,9 @@ const GET_E_REFERRALS = "Services/Patients.svc/REST/GetEReferrals"; const GET_ANCILLARY_ORDERS = 'Services/Doctors.svc/REST/GetOnlineAncillaryOrderList'; +const GET_ANCILLARY_ORDERS_DETAILS = + 'Services/Doctors.svc/REST/GetOnlineAncillaryOrderProcList'; + //Pharmacy wishlist // const GET_WISHLIST = "http://swd-pharapp-01:7200/api/shopping_cart_items/"; diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index afcce431..3217d084 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -1159,7 +1159,7 @@ const Map localizedValues = { "ar": "Connected with HMG Network,\n\nBut failed to access HMG services" }, "offerAndPackages": {"en": "Offers And Packages", "ar": "العروض والباقات"}, - "InvoiceNo": {"en": " Invoice No", "ar": "رقم الفاتورة"}, + "InvoiceNo": {"en": "Invoice No", "ar": "رقم الفاتورة"}, "SpecialResult": {"en": " Special Result", "ar": "نتيجة خاصة"}, "GeneralResult": {"en": "General Result", "ar": "نتيجة عامة"}, "show-more-btn": {"en": "Flow Chart", "ar": "النتائج التراكمية"}, @@ -1652,7 +1652,10 @@ const Map localizedValues = { "enterReadingValue": {"en": "Enter the reading value", "ar": "ادخل القيمة"}, "result": {"en": "Result", "ar": "النتيجة"}, "sort": {"en": "Sort", "ar": "فرز"}, - "bloodSugarConversion": {"en": "Blood Sugar Conversion", "ar": "السكر في الدم"}, + "bloodSugarConversion": { + "en": "Blood Sugar Conversion", + "ar": "السكر في الدم" + }, "convertBloodSugarStatement": { "en": "Convert blood sugar/glucose from mmol/l (UK standard) to mg/dlt (US standard) and vice versa.", @@ -1954,6 +1957,9 @@ const Map localizedValues = { }, "order-overview": {"en": "Order Overview", "ar": "ملخص الطلب"}, "shipping-address": {"en": "Delivery Address", "ar": "عنوان التوصيل"}, - "ancillary-orders": {"en": "Ancillary Orders", "ar": "الأوامر التبعية"}, - + "ancillary-orders": {"en": "Ancillary Orders", "ar": "الأوامر التبعية"}, + "MRN": {"en": "MRN", "ar": "ایم آر این"}, + "appointment-date": {"en": "Appointment Date", "ar": "تقرری کی تاریخ"}, + "appointment-no": {"en": "Appointment No", "ar": "تقرری نمبر"}, + "insurance-id": {"en": "Insurance ID", "ar": "انشورنس ID"}, }; diff --git a/lib/core/service/ancillary_orders_service.dart b/lib/core/service/ancillary_orders_service.dart index 5adf5305..b9d14a06 100644 --- a/lib/core/service/ancillary_orders_service.dart +++ b/lib/core/service/ancillary_orders_service.dart @@ -1,10 +1,14 @@ import 'package:diplomaticquarterapp/config/config.dart'; import 'package:diplomaticquarterapp/core/service/base_service.dart'; import 'package:diplomaticquarterapp/models/anicllary-orders/ancillary_order_list_model.dart'; +import 'package:diplomaticquarterapp/models/anicllary-orders/ancillary_order_proc_model.dart'; class AncillaryOrdersService extends BaseService { List _ancillaryLists = List(); List get ancillaryLists => _ancillaryLists; + List _ancillaryProcLists = List(); + List get ancillaryProcLists => + _ancillaryProcLists; Future getOrders() async { Map body = Map(); @@ -13,6 +17,7 @@ class AncillaryOrdersService extends BaseService { await baseAppClient.post(GET_ANCILLARY_ORDERS, onSuccess: (dynamic response, int statusCode) { + _ancillaryLists = []; response['AncillaryOrderList'].forEach((item) { ancillaryLists.add(AncillaryOrdersListModel.fromJson(item)); }); @@ -21,4 +26,179 @@ class AncillaryOrdersService extends BaseService { super.error = error; }, body: body); } + + Future getOrdersDetails(appointmentNo, orderNo) async { + Map body = Map(); + + hasError = false; + + await baseAppClient.post(GET_ANCILLARY_ORDERS_DETAILS, + onSuccess: (dynamic response, int statusCode) { + _ancillaryProcLists = []; + response['AncillaryOrderProcList'] = [ + { + "AncillaryOrderProcList": [ + { + "ApprovalLineItemNo": 0, + "ApprovalNo": 0, + "ApprovalStatus": "", + "ApprovalStatusID": 0, + "CompanyShare": 501.3, + "CompanyShareWithTax": 576.5, + "CompanyTaxAmount": 75.19, + "DiscountAmount": 55.7, + "DiscountCategory": 1, + "DiscountType": "P", + "DiscountTypeValue": 10, + "IsApprovalCreated": false, + "IsApprovalRequired": false, + "IsCovered": false, + "OrderDate": "/Date(1601758800000+0300)/", + "OrderLineItemNo": 1, + "OrderNo": 2020000001, + "PartnerID": 0, + "PartnerShare": 0, + "PartnerShareType": "P", + "PatientShare": 0, + "PatientShareWithTax": 0, + "PatientTaxAmount": 0, + "ProcPrice": 557, + "ProcedureCategoryID": 2, + "ProcedureCategoryName": "LABORATORY", + "ProcedureID": "02013001", + "ProcedureName": "11-DESOXYCORTISOL (COMPOUND S) - S.O", + "TaxAmount": 75.19, + "TaxPct": 15 + }, + { + "ApprovalLineItemNo": 0, + "ApprovalNo": 0, + "ApprovalStatus": "", + "ApprovalStatusID": 0, + "CompanyShare": 90, + "CompanyShareWithTax": 103.5, + "CompanyTaxAmount": 13.5, + "DiscountAmount": 10, + "DiscountCategory": 1, + "DiscountType": "P", + "DiscountTypeValue": 10, + "IsApprovalCreated": false, + "IsApprovalRequired": true, + "IsCovered": false, + "OrderDate": "/Date(1601758800000+0300)/", + "OrderLineItemNo": 4, + "OrderNo": 2020000001, + "PartnerID": 0, + "PartnerShare": 0, + "PartnerShareType": "P", + "PatientShare": 0, + "PatientShareWithTax": 0, + "PatientTaxAmount": 0, + "ProcPrice": 100, + "ProcedureCategoryID": 2, + "ProcedureCategoryName": "LABORATORY", + "ProcedureID": "02014011", + "ProcedureName": "CBC (COMPLETE BLOOD COUNT PROFILE)", + "TaxAmount": 13.5, + "TaxPct": 15 + }, + { + "ApprovalLineItemNo": 0, + "ApprovalNo": 0, + "ApprovalStatus": "", + "ApprovalStatusID": 0, + "CompanyShare": 347.76, + "CompanyShareWithTax": 399.92, + "CompanyTaxAmount": 52.16, + "DiscountAmount": 38.64, + "DiscountCategory": 1, + "DiscountType": "P", + "DiscountTypeValue": 10, + "IsApprovalCreated": false, + "IsApprovalRequired": false, + "IsCovered": false, + "OrderDate": "/Date(1601758800000+0300)/", + "OrderLineItemNo": 3, + "OrderNo": 2020000001, + "PartnerID": 0, + "PartnerShare": 0, + "PartnerShareType": "P", + "PatientShare": 0, + "PatientShareWithTax": 0, + "PatientTaxAmount": 0, + "ProcPrice": 386.4, + "ProcedureCategoryID": 2, + "ProcedureCategoryName": "LABORATORY", + "ProcedureID": "02019302", + "ProcedureName": "21-HYDROXYLASE ABS - S.O", + "TaxAmount": 52.16, + "TaxPct": 15 + }, + { + "ApprovalLineItemNo": 0, + "ApprovalNo": 0, + "ApprovalStatus": "", + "ApprovalStatusID": 0, + "CompanyShare": 1323, + "CompanyShareWithTax": 1521.45, + "CompanyTaxAmount": 198.45, + "DiscountAmount": 147, + "DiscountCategory": 1, + "DiscountType": "P", + "DiscountTypeValue": 10, + "IsApprovalCreated": false, + "IsApprovalRequired": true, + "IsCovered": false, + "OrderDate": "/Date(1601758800000+0300)/", + "OrderLineItemNo": 5, + "OrderNo": 2020000001, + "PartnerID": 0, + "PartnerShare": 0, + "PartnerShareType": "P", + "PatientShare": 0, + "PatientShareWithTax": 0, + "PatientTaxAmount": 0, + "ProcPrice": 1470, + "ProcedureCategoryID": 3, + "ProcedureCategoryName": "RADIOLOGY", + "ProcedureID": "03033065", + "ProcedureName": "CT SCAN - ABDOMEN (WITH CONTRAST)", + "TaxAmount": 198.45, + "TaxPct": 15 + } + ], + "AppointmentDate": "/Date(1601499600000+0300)/", + "AppointmentNo": 2016053756, + "ClinicID": 1, + "ClinicName": "INTERNAL MEDICINE CLINIC", + "CompanyID": 0, + "CompanyName": "Blood Donation Investigation", + "DoctorID": 1485, + "DoctorName": "ANAS ABDULLAH", + "ErrCode": null, + "GroupID": 2, + "InsurancePolicyNo": "45976500", + "Message": "Success", + "PatientCardID": "232332323", + "PatientID": 3072055, + "PatientName": "MAYA KHALED SADDIQ", + "PatientType": 1, + "PolicyID": 2, + "PolicyName": "Test", + "ProjectID": 15, + "SetupID": "010266", + "StatusCode": 1, + "SubCategoryID": 2, + "SubPolicyNo": "234234" + } + ]; + + response['AncillaryOrderProcList'].forEach((item) { + ancillaryProcLists.add(AncillaryOrdersListProcListModel.fromJson(item)); + }); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: body); + } } diff --git a/lib/core/viewModels/ancillary_orders_view_model.dart b/lib/core/viewModels/ancillary_orders_view_model.dart index 2d92a402..77eb4237 100644 --- a/lib/core/viewModels/ancillary_orders_view_model.dart +++ b/lib/core/viewModels/ancillary_orders_view_model.dart @@ -1,4 +1,6 @@ import 'package:diplomaticquarterapp/core/service/ancillary_orders_service.dart'; +import 'package:diplomaticquarterapp/models/anicllary-orders/ancillary_order_list_model.dart'; +import 'package:diplomaticquarterapp/models/anicllary-orders/ancillary_order_proc_model.dart'; import 'base_view_model.dart'; import '../../locator.dart'; @@ -8,7 +10,10 @@ class AnciallryOrdersViewModel extends BaseViewModel { bool hasError = false; AncillaryOrdersService _ancillaryService = locator(); - + List get ancillaryLists => + _ancillaryService.ancillaryLists; + List get ancillaryListsDetails => + _ancillaryService.ancillaryProcLists; Future getOrders() async { hasError = false; setState(ViewState.Busy); @@ -19,4 +24,15 @@ class AnciallryOrdersViewModel extends BaseViewModel { } else setState(ViewState.Idle); } + + Future getOrdersDetails(appointmentNo, orderNo) async { + hasError = false; + setState(ViewState.Busy); + await _ancillaryService.getOrdersDetails(appointmentNo, orderNo); + if (_ancillaryService.hasError) { + error = _ancillaryService.error; + setState(ViewState.ErrorLocal); + } else + setState(ViewState.Idle); + } } diff --git a/lib/locator.dart b/lib/locator.dart index 7803b6a9..9bc077f7 100644 --- a/lib/locator.dart +++ b/lib/locator.dart @@ -1,7 +1,9 @@ import 'package:diplomaticquarterapp/core/service/AlHabibMedicalService/H2O_service.dart'; +import 'package:diplomaticquarterapp/core/service/ancillary_orders_service.dart'; import 'package:diplomaticquarterapp/core/service/parmacyModule/prescription_service.dart'; import 'package:diplomaticquarterapp/core/service/qr_service.dart'; import 'package:diplomaticquarterapp/core/viewModels/AlHabibMedicalService/H2O_view_model.dart'; +import 'package:diplomaticquarterapp/core/viewModels/ancillary_orders_view_model.dart'; import 'package:diplomaticquarterapp/core/viewModels/child_vaccines/user_information_view_model.dart'; import 'package:diplomaticquarterapp/core/viewModels/AlHabibMedicalService/home_health_care_view_model.dart'; import 'package:diplomaticquarterapp/core/viewModels/dashboard_view_model.dart'; @@ -192,7 +194,7 @@ void setupLocator() { locator.registerLazySingleton(() => DeleteBabyService()); locator.registerLazySingleton(() => VaccinationTableService()); - + locator.registerLazySingleton(() => AncillaryOrdersService()); //pharmacy // locator.registerLazySingleton(() => PharmacyCategoriseService()); // locator.registerLazySingleton(() => OffersCategoriseService()); @@ -220,7 +222,6 @@ void setupLocator() { locator.registerLazySingleton(() => PrescriptionService()); locator.registerLazySingleton(() => RecommendedProductService()); - locator.registerLazySingleton(() => PrivilegeService()); locator.registerLazySingleton(() => WeatherService()); locator.registerLazySingleton(() => TermsConditionsService()); @@ -309,4 +310,5 @@ void setupLocator() { locator.registerLazySingleton( () => GeofencingServices()); // Geofencing Services locator.registerFactory(() => TermsConditionsViewModel()); + locator.registerFactory(() => AnciallryOrdersViewModel()); } diff --git a/lib/models/anicllary-orders/ancillary_order_proc_model.dart b/lib/models/anicllary-orders/ancillary_order_proc_model.dart new file mode 100644 index 00000000..7322d11a --- /dev/null +++ b/lib/models/anicllary-orders/ancillary_order_proc_model.dart @@ -0,0 +1,249 @@ +class AncillaryOrdersListProcListModel { + List ancillaryOrderProcList; + String appointmentDate; + dynamic appointmentNo; + dynamic clinicID; + String clinicName; + dynamic companyID; + String companyName; + dynamic doctorID; + String doctorName; + Null errCode; + dynamic groupID; + String insurancePolicyNo; + String message; + String patientCardID; + dynamic patientID; + String patientName; + dynamic patientType; + dynamic policyID; + String policyName; + dynamic projectID; + String setupID; + dynamic statusCode; + dynamic subCategoryID; + String subPolicyNo; + + AncillaryOrdersListProcListModel( + {this.ancillaryOrderProcList, + this.appointmentDate, + this.appointmentNo, + this.clinicID, + this.clinicName, + this.companyID, + this.companyName, + this.doctorID, + this.doctorName, + this.errCode, + this.groupID, + this.insurancePolicyNo, + this.message, + this.patientCardID, + this.patientID, + this.patientName, + this.patientType, + this.policyID, + this.policyName, + this.projectID, + this.setupID, + this.statusCode, + this.subCategoryID, + this.subPolicyNo}); + + AncillaryOrdersListProcListModel.fromJson(Map json) { + if (json['AncillaryOrderProcList'] != null) { + ancillaryOrderProcList = new List(); + json['AncillaryOrderProcList'].forEach((v) { + ancillaryOrderProcList.add(new AncillaryOrderProcList.fromJson(v)); + }); + } + appointmentDate = json['AppointmentDate']; + appointmentNo = json['AppointmentNo']; + clinicID = json['ClinicID']; + clinicName = json['ClinicName']; + companyID = json['CompanyID']; + companyName = json['CompanyName']; + doctorID = json['DoctorID']; + doctorName = json['DoctorName']; + errCode = json['ErrCode']; + groupID = json['GroupID']; + insurancePolicyNo = json['InsurancePolicyNo']; + message = json['Message']; + patientCardID = json['PatientCardID']; + patientID = json['PatientID']; + patientName = json['PatientName']; + patientType = json['PatientType']; + policyID = json['PolicyID']; + policyName = json['PolicyName']; + projectID = json['ProjectID']; + setupID = json['SetupID']; + statusCode = json['StatusCode']; + subCategoryID = json['SubCategoryID']; + subPolicyNo = json['SubPolicyNo']; + } + + Map toJson() { + final Map data = new Map(); + if (this.ancillaryOrderProcList != null) { + data['AncillaryOrderProcList'] = + this.ancillaryOrderProcList.map((v) => v.toJson()).toList(); + } + data['AppointmentDate'] = this.appointmentDate; + data['AppointmentNo'] = this.appointmentNo; + data['ClinicID'] = this.clinicID; + data['ClinicName'] = this.clinicName; + data['CompanyID'] = this.companyID; + data['CompanyName'] = this.companyName; + data['DoctorID'] = this.doctorID; + data['DoctorName'] = this.doctorName; + data['ErrCode'] = this.errCode; + data['GroupID'] = this.groupID; + data['InsurancePolicyNo'] = this.insurancePolicyNo; + data['Message'] = this.message; + data['PatientCardID'] = this.patientCardID; + data['PatientID'] = this.patientID; + data['PatientName'] = this.patientName; + data['PatientType'] = this.patientType; + data['PolicyID'] = this.policyID; + data['PolicyName'] = this.policyName; + data['ProjectID'] = this.projectID; + data['SetupID'] = this.setupID; + data['StatusCode'] = this.statusCode; + data['SubCategoryID'] = this.subCategoryID; + data['SubPolicyNo'] = this.subPolicyNo; + return data; + } +} + +class AncillaryOrderProcList { + dynamic approvalLineItemNo; + dynamic approvalNo; + String approvalStatus; + dynamic approvalStatusID; + dynamic companyShare; + dynamic companyShareWithTax; + dynamic companyTaxAmount; + dynamic discountAmount; + dynamic discountCategory; + String discountType; + dynamic discountTypeValue; + bool isApprovalCreated; + bool isApprovalRequired; + bool isCovered; + String orderDate; + dynamic orderLineItemNo; + dynamic orderNo; + dynamic partnerID; + dynamic partnerShare; + String partnerShareType; + dynamic patientShare; + dynamic patientShareWithTax; + dynamic patientTaxAmount; + dynamic procPrice; + dynamic procedureCategoryID; + String procedureCategoryName; + String procedureID; + String procedureName; + dynamic taxAmount; + dynamic taxPct; + + AncillaryOrderProcList( + {this.approvalLineItemNo, + this.approvalNo, + this.approvalStatus, + this.approvalStatusID, + this.companyShare, + this.companyShareWithTax, + this.companyTaxAmount, + this.discountAmount, + this.discountCategory, + this.discountType, + this.discountTypeValue, + this.isApprovalCreated, + this.isApprovalRequired, + this.isCovered, + this.orderDate, + this.orderLineItemNo, + this.orderNo, + this.partnerID, + this.partnerShare, + this.partnerShareType, + this.patientShare, + this.patientShareWithTax, + this.patientTaxAmount, + this.procPrice, + this.procedureCategoryID, + this.procedureCategoryName, + this.procedureID, + this.procedureName, + this.taxAmount, + this.taxPct}); + + AncillaryOrderProcList.fromJson(Map json) { + approvalLineItemNo = json['ApprovalLineItemNo']; + approvalNo = json['ApprovalNo']; + approvalStatus = json['ApprovalStatus']; + approvalStatusID = json['ApprovalStatusID']; + companyShare = json['CompanyShare']; + companyShareWithTax = json['CompanyShareWithTax']; + companyTaxAmount = json['CompanyTaxAmount']; + discountAmount = json['DiscountAmount']; + discountCategory = json['DiscountCategory']; + discountType = json['DiscountType']; + discountTypeValue = json['DiscountTypeValue']; + isApprovalCreated = json['IsApprovalCreated']; + isApprovalRequired = json['IsApprovalRequired']; + isCovered = json['IsCovered']; + orderDate = json['OrderDate']; + orderLineItemNo = json['OrderLineItemNo']; + orderNo = json['OrderNo']; + partnerID = json['PartnerID']; + partnerShare = json['PartnerShare']; + partnerShareType = json['PartnerShareType']; + patientShare = json['PatientShare']; + patientShareWithTax = json['PatientShareWithTax']; + patientTaxAmount = json['PatientTaxAmount']; + procPrice = json['ProcPrice']; + procedureCategoryID = json['ProcedureCategoryID']; + procedureCategoryName = json['ProcedureCategoryName']; + procedureID = json['ProcedureID']; + procedureName = json['ProcedureName']; + taxAmount = json['TaxAmount']; + taxPct = json['TaxPct']; + } + + Map toJson() { + final Map data = new Map(); + data['ApprovalLineItemNo'] = this.approvalLineItemNo; + data['ApprovalNo'] = this.approvalNo; + data['ApprovalStatus'] = this.approvalStatus; + data['ApprovalStatusID'] = this.approvalStatusID; + data['CompanyShare'] = this.companyShare; + data['CompanyShareWithTax'] = this.companyShareWithTax; + data['CompanyTaxAmount'] = this.companyTaxAmount; + data['DiscountAmount'] = this.discountAmount; + data['DiscountCategory'] = this.discountCategory; + data['DiscountType'] = this.discountType; + data['DiscountTypeValue'] = this.discountTypeValue; + data['IsApprovalCreated'] = this.isApprovalCreated; + data['IsApprovalRequired'] = this.isApprovalRequired; + data['IsCovered'] = this.isCovered; + data['OrderDate'] = this.orderDate; + data['OrderLineItemNo'] = this.orderLineItemNo; + data['OrderNo'] = this.orderNo; + data['PartnerID'] = this.partnerID; + data['PartnerShare'] = this.partnerShare; + data['PartnerShareType'] = this.partnerShareType; + data['PatientShare'] = this.patientShare; + data['PatientShareWithTax'] = this.patientShareWithTax; + data['PatientTaxAmount'] = this.patientTaxAmount; + data['ProcPrice'] = this.procPrice; + data['ProcedureCategoryID'] = this.procedureCategoryID; + data['ProcedureCategoryName'] = this.procedureCategoryName; + data['ProcedureID'] = this.procedureID; + data['ProcedureName'] = this.procedureName; + data['TaxAmount'] = this.taxAmount; + data['TaxPct'] = this.taxPct; + return data; + } +} diff --git a/lib/pages/AlHabibMedicalService/all_habib_medical_service_page.dart b/lib/pages/AlHabibMedicalService/all_habib_medical_service_page.dart index fe8f73f6..877f9fb7 100644 --- a/lib/pages/AlHabibMedicalService/all_habib_medical_service_page.dart +++ b/lib/pages/AlHabibMedicalService/all_habib_medical_service_page.dart @@ -5,6 +5,7 @@ import 'package:diplomaticquarterapp/models/Authentication/authenticated_user.da import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/%E2%80%8B%20health_calculators.dart'; import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/E-Referral/e_referral_index_page.dart'; import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/E-Referral/e_referral_page.dart'; +import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrders.dart'; import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/h2o/h2o_index_page.dart'; import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/health-weather/health-weather-indicator.dart'; import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/health_converter.dart'; @@ -203,7 +204,7 @@ class _AllHabibMedicalServiceState extends State { onTap: () => Navigator.push( context, FadePage( - page: PaymentService(), + page: AnicllaryOrders(), ), ), imageLocation: diff --git a/lib/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrders.dart b/lib/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrders.dart index 57b134bf..b229775a 100644 --- a/lib/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrders.dart +++ b/lib/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrders.dart @@ -1,16 +1,13 @@ import 'package:diplomaticquarterapp/core/viewModels/ancillary_orders_view_model.dart'; -import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/health_calculator/body_fat/body_fat.dart'; -import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/health_calculator/bmi_calculator/bmi_calculator.dart'; +import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrdersDetails.dart'; import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/health_calculator/calorie_calculator/calorie_calculator.dart'; -import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/health_calculator/carbs/carbs.dart'; -import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/health_calculator/ovulation_period/ovulation_period.dart'; import 'package:diplomaticquarterapp/pages/base/base_view.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; -import 'package:diplomaticquarterapp/widgets/data_display/medical/medical_profile_item.dart'; import 'package:diplomaticquarterapp/widgets/data_display/text.dart'; import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; import 'package:flutter/material.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:diplomaticquarterapp/uitl/date_uitl.dart'; class AnicllaryOrders extends StatefulWidget { @override @@ -36,8 +33,145 @@ class _AnicllaryOrdersState extends State onModelReady: (model) => model.getOrders(), builder: (_, model, widget) => AppScaffold( isShowAppBar: true, - appBarTitle: TranslationBase.of(context).parking, + baseViewModel: model, + appBarTitle: TranslationBase.of(context).anicllaryOrders, body: SingleChildScrollView( - padding: EdgeInsets.all(12), child: Container()))); + padding: EdgeInsets.all(12), + child: model.ancillaryLists.length > 0 + ? Column(children: [ + getPatientInfo(model), + getAncillaryOrdersList(model) + ]) + : SizedBox()))); + } + + Widget getPatientInfo(AnciallryOrdersViewModel model) { + print(model.ancillaryLists); + return Padding( + child: Column( + children: [ + Row( + children: [ + Texts( + TranslationBase.of(context).mrn, + fontWeight: FontWeight.bold, + fontSize: 22, + ), + Texts( + " : ", + fontSize: 20, + ), + Texts( + model.ancillaryLists[0].patientID.toString(), + ) + ], + ), + Row( + children: [ + Texts( + TranslationBase.of(context).patientName, + fontWeight: FontWeight.bold, + fontSize: 20, + ), + Texts( + " : ", + fontSize: 20, + ), + Texts( + model.ancillaryLists[0].patientName, + ) + ], + ), + Divider() + ], + ), + padding: EdgeInsets.only(top: 5.0, bottom: 10.0), + ); + } + + Widget getAncillaryOrdersList(AnciallryOrdersViewModel model) { + return Column( + children: model.ancillaryLists[0].ancillaryOrderList + .map( + (item) => InkWell( + onTap: () { + ancillaryOrdersDetails(item); + }, + child: Container( + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + width: 0.5, + ))), + padding: EdgeInsets.all(5), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.all(3), + child: Row( + mainAxisAlignment: + MainAxisAlignment.start, + children: [ + Texts( + TranslationBase.of(context) + .appointmentNo + + ' : ', + fontWeight: FontWeight.bold, + ), + Texts(item.appointmentNo.toString()) + ], + )), + Padding( + padding: EdgeInsets.all(3), + child: Row( + children: [ + Texts( + TranslationBase.of(context) + .appointmentDate + + ' : ', + fontWeight: FontWeight.bold), + Texts(DateUtil.getFormattedDate( + DateUtil.convertStringToDate( + item.appointmentDate), + "MMM dd,yyyy")) + ], + )), + Padding( + padding: EdgeInsets.all(3), + child: Row( + children: [ + Texts( + TranslationBase.of(context) + .doctorName + + ' : ', + fontWeight: FontWeight.bold), + Texts(item.doctorName.toString()) + ], + )), + Divider( + color: Colors.black12, + height: 1, + ) + ]), + Icon( + Icons.arrow_right, + size: 25, + ) + ]))), + ) + .toList()); + } + + ancillaryOrdersDetails(item) { + Navigator.push( + context, + FadePage( + page: AnicllaryOrdersDetails(item.appointmentNo, item.orderNo), + ), + ); } } diff --git a/lib/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrdersDetails.dart b/lib/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrdersDetails.dart new file mode 100644 index 00000000..9fb7e7d2 --- /dev/null +++ b/lib/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrdersDetails.dart @@ -0,0 +1,196 @@ +import 'package:diplomaticquarterapp/core/viewModels/ancillary_orders_view_model.dart'; +import 'package:diplomaticquarterapp/pages/base/base_view.dart'; +import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; +import 'package:diplomaticquarterapp/widgets/data_display/text.dart'; +import 'package:flutter/material.dart'; +import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:diplomaticquarterapp/uitl/date_uitl.dart'; +import "package:collection/collection.dart"; + +class AnicllaryOrdersDetails extends StatefulWidget { + final dynamic appoNo; + final dynamic orderNo; + AnicllaryOrdersDetails(this.appoNo, this.orderNo); + @override + _AnicllaryOrdersState createState() => _AnicllaryOrdersState(); +} + +class _AnicllaryOrdersState extends State + with SingleTickerProviderStateMixin { + void initState() { + super.initState(); + } + + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return BaseView( + onModelReady: (model) => + model.getOrdersDetails(widget.appoNo, widget.orderNo), + builder: (_, model, widget) => AppScaffold( + isShowAppBar: true, + baseViewModel: model, + appBarTitle: TranslationBase.of(context).anicllaryOrders, + body: SingleChildScrollView( + padding: EdgeInsets.all(12), + child: model.ancillaryListsDetails.length > 0 + ? Column(children: [ + getPatientInfo(model), + getInvoiceDetails(model), + getInsuranceDetails(model), + getAncillaryDetails(model) + ]) + : SizedBox()))); + } + + Widget getPatientInfo(AnciallryOrdersViewModel model) { + print(model.ancillaryListsDetails); + return Padding( + child: Column( + children: [ + Row( + children: [ + Texts( + TranslationBase.of(context).mrn, + fontWeight: FontWeight.bold, + fontSize: 22, + ), + Texts( + " : ", + fontSize: 20, + ), + Texts( + model.ancillaryListsDetails[0].patientID.toString(), + ) + ], + ), + Row( + children: [ + Texts( + TranslationBase.of(context).patientName, + fontWeight: FontWeight.bold, + fontSize: 20, + ), + Texts( + " : ", + fontSize: 20, + ), + Texts( + model.ancillaryLists[0].patientName, + ) + ], + ), + Divider( + color: Colors.black26, + ) + ], + ), + padding: EdgeInsets.only(top: 5.0, bottom: 5.0), + ); + } + + Widget getInvoiceDetails(model) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Texts( + TranslationBase.of(context).invoiceNo, + fontWeight: FontWeight.bold, + ), + Texts(" : "), + Texts( + model.ancillaryListsDetails[0].appointmentNo.toString(), + ) + ], + ), + Row( + children: [ + Texts( + TranslationBase.of(context).date, + fontWeight: FontWeight.bold, + ), + Texts(" : "), + Texts( + DateUtil.getFormattedDate( + DateUtil.convertStringToDate( + model.ancillaryListsDetails[0].appointmentDate), + "MMM dd,yyyy"), + ) + ], + ), + Row( + children: [ + Texts( + TranslationBase.of(context).date, + fontWeight: FontWeight.bold, + ), + Texts(" : "), + Texts( + model.ancillaryListsDetails[0].doctorName, + ), + ], + ), + SizedBox( + height: 10, + ), + Divider( + color: Colors.black26, + ) + ], + ); + } + + Widget getInsuranceDetails(model) { + return Padding( + padding: EdgeInsets.only(top: 10, bottom: 10), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Texts( + TranslationBase.of(context).insurance, + fontWeight: FontWeight.bold, + ), + Texts( + TranslationBase.of(context).insuranceID, + fontWeight: FontWeight.bold, + ) + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Texts( + model.ancillaryListsDetails[0].policyName, + ), + Texts( + model.ancillaryListsDetails[0].insurancePolicyNo, + ) + ], + ), + SizedBox( + height: 15, + ), + Divider( + color: Colors.red[800], + thickness: 3, + ) + ], + )); + } + + Widget getAncillaryDetails(model) { + var newMap = groupBy(model.ancillaryListsDetails[0].ancillaryOrderProcList, + (obj) => obj.procedureCategoryName); + print(newMap); + return Padding( + padding: EdgeInsets.only(top: 10, bottom: 10), + child: Column(children: [])); + } +} diff --git a/lib/uitl/translations_delegate_base.dart b/lib/uitl/translations_delegate_base.dart index e02453a6..a24be50a 100644 --- a/lib/uitl/translations_delegate_base.dart +++ b/lib/uitl/translations_delegate_base.dart @@ -1394,9 +1394,12 @@ class TranslationBase { String get convertFrom => localizedValues["convertFrom"][locale.languageCode]; String get result => localizedValues["result"][locale.languageCode]; String get sort => localizedValues["sort"][locale.languageCode]; - String get bloodSugarConversion => localizedValues["bloodSugarConversion"][locale.languageCode]; - String get convertCholesterolStatement => localizedValues["convertCholesterolStatement"][locale.languageCode]; - String get triglyceridesConvertStatement => localizedValues["triglyceridesConvertStatement"][locale.languageCode]; + String get bloodSugarConversion => + localizedValues["bloodSugarConversion"][locale.languageCode]; + String get convertCholesterolStatement => + localizedValues["convertCholesterolStatement"][locale.languageCode]; + String get triglyceridesConvertStatement => + localizedValues["triglyceridesConvertStatement"][locale.languageCode]; String get bloodDEnterDesc => localizedValues["bloodD-enter-desc"][locale.languageCode]; String get viewTermsConditions => @@ -1572,6 +1575,13 @@ class TranslationBase { String get covidAlert => localizedValues["covid-alert"][locale.languageCode]; String get anicllaryOrders => localizedValues["ancillary-orders"][locale.languageCode]; + String get mrn => localizedValues["MRN"][locale.languageCode]; + String get appointmentDate => + localizedValues["appointment-date"][locale.languageCode]; + String get appointmentNo => + localizedValues["appointment-no"][locale.languageCode]; + String get insuranceID => + localizedValues["insurance-id"][locale.languageCode]; } class TranslationBaseDelegate extends LocalizationsDelegate { diff --git a/lib/widgets/others/floating_button_search.dart b/lib/widgets/others/floating_button_search.dart index 3e3bae5a..69251773 100644 --- a/lib/widgets/others/floating_button_search.dart +++ b/lib/widgets/others/floating_button_search.dart @@ -834,11 +834,13 @@ class _FloatingSearchButton extends State if (isInit == true) { event.setValue({"animationEnable": 'true'}); } - if (isArabic == false && results['ReturnMessage'] != null) { + if (isArabic == false && + results['ReturnMessage'] != null && + isInit == false) { await flutterTts .setVoice({"name": "en-au-x-aub-network", "locale": "en-AU"}); await flutterTts.speak(results['ReturnMessage']); - } else if (results['ReturnMessage_Ar'] != null) { + } else if (results['ReturnMessage_Ar'] != null && isInit == false) { await flutterTts .setVoice({"name": "ar-xa-x-ard-network", "locale": "ar"}); await flutterTts.speak(results['ReturnMessage_Ar']); @@ -889,6 +891,21 @@ class _FloatingSearchButton extends State stopAnimation({isInit}) async { if (isInit == true) { IS_TEXT_COMPLETED = true; + Future.delayed(const Duration(seconds: 10), () { + event.setValue({"animationEnable": 'false'}); + setState(() { + this.networkImage = null; + this.isAnimationEnable = false; + }); + }); + } else { + flutterTts.setCompletionHandler(() async { + event.setValue({"animationEnable": 'false'}); + setState(() { + this.networkImage = null; + this.isAnimationEnable = false; + }); + }); } flutterTts.setCompletionHandler(() async { event.setValue({"animationEnable": 'false'}); From 80d96ba785403c4c3cc4eb70b2ac627da1fd21ed Mon Sep 17 00:00:00 2001 From: Sultan Khan Date: Thu, 11 Mar 2021 12:27:08 +0300 Subject: [PATCH 10/26] Privilege issue fixed --- lib/pages/DrawerPages/family/my-family.dart | 12 +++++++----- lib/widgets/drawer/app_drawer_widget.dart | 3 ++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/pages/DrawerPages/family/my-family.dart b/lib/pages/DrawerPages/family/my-family.dart index a2312220..0a5c5091 100644 --- a/lib/pages/DrawerPages/family/my-family.dart +++ b/lib/pages/DrawerPages/family/my-family.dart @@ -57,7 +57,8 @@ class _MyFamily extends State with TickerProviderStateMixin { ProjectViewModel projectViewModel; AuthenticatedUser user; VitalSignService _vitalSignService = locator(); - PharmacyModuleViewModel pharmacyModuleViewModel = locator(); + PharmacyModuleViewModel pharmacyModuleViewModel = + locator(); var isVaiable = false; @override @@ -707,10 +708,11 @@ class _MyFamily extends State with TickerProviderStateMixin { loginAfter(result, context) async { GifLoaderDialogUtils.hideDialog(context); var currentLang = await sharedPref.getString(APP_LANGUAGE); - result = list.CheckActivationCode.fromJson(result); - var familyFile = await sharedPref.getObject(FAMILY_FILE); Provider.of(context, listen: false) .setPrivilege(privilegeList: result, isLoginChild: true); + result = list.CheckActivationCode.fromJson(result); + var familyFile = await sharedPref.getObject(FAMILY_FILE); + result = list.CheckActivationCode.fromJson(result); var mainUser = await sharedPref.getObject(MAIN_USER); var bloodType = await sharedPref.getString(BLOOD_TYPE); @@ -731,8 +733,8 @@ class _MyFamily extends State with TickerProviderStateMixin { Provider.of(context, listen: false) .setUser(authenticatedUserObject.user); - await pharmacyModuleViewModel.generatePharmacyToken().then((value) async { - if(pharmacyModuleViewModel.error.isNotEmpty) + await pharmacyModuleViewModel.generatePharmacyToken().then((value) async { + if (pharmacyModuleViewModel.error.isNotEmpty) await pharmacyModuleViewModel.createUser(); }); diff --git a/lib/widgets/drawer/app_drawer_widget.dart b/lib/widgets/drawer/app_drawer_widget.dart index 83b0df5f..dd5f65c1 100644 --- a/lib/widgets/drawer/app_drawer_widget.dart +++ b/lib/widgets/drawer/app_drawer_widget.dart @@ -525,9 +525,10 @@ class _AppDrawerState extends State { loginAfter(result, context) async { Utils.hideProgressDialog(); - result = CheckActivationCode.fromJson(result); Provider.of(context, listen: false) .setPrivilege(privilegeList: result, isLoginChild: true); + result = CheckActivationCode.fromJson(result); + var familyFile = await sharedPref.getObject(FAMILY_FILE); var currentLang = await sharedPref.getString(APP_LANGUAGE); var mainUser = await sharedPref.getObject(MAIN_USER); From ad88f6de043e1b1ea91702e88831b96f23109235 Mon Sep 17 00:00:00 2001 From: Mohammad Aljammal Date: Mon, 15 Mar 2021 11:33:04 +0200 Subject: [PATCH 11/26] fix theme issues --- lib/config/localized_values.dart | 2 +- lib/pages/settings/general_setting.dart | 16 ++++++++-------- lib/theme/theme_value.dart | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index 4cababb4..ecd9ee03 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -365,7 +365,7 @@ const Map localizedValues = { 'painScale': {'en': 'Pain Scale', 'ar': 'مقياس الألم'}, 'weight': {'en': 'Weight', 'ar': 'الوزن'}, 'height': {'en': 'Height', 'ar': 'الطول'}, - 'heart': {'en': 'Heart', 'ar': 'قلب'}, + 'heart': {'en': 'Heart Rate', 'ar': 'معدل النبض'}, "heightUnit": {"en": "height unit", "ar": "وحدة الطول"}, "weightUnit": {"en": "Weight Unit", "ar": "وحدة الوزن"}, "request": {"en": "Request", "ar": "طلبات الاضافة"}, diff --git a/lib/pages/settings/general_setting.dart b/lib/pages/settings/general_setting.dart index 14f24181..8c3177dc 100644 --- a/lib/pages/settings/general_setting.dart +++ b/lib/pages/settings/general_setting.dart @@ -40,7 +40,7 @@ class _GeneralSettings extends State return Container( child: ListView(scrollDirection: Axis.vertical, children: [ Container( - color: Theme.of(context).primaryColor, + color: Theme.of(context).scaffoldBackgroundColor, padding: EdgeInsets.all(10), child: AppText( TranslationBase.of(context).modes, @@ -48,7 +48,7 @@ class _GeneralSettings extends State ), ), Container( - color: Theme.of(context).primaryColor, + color: Theme.of(context).scaffoldBackgroundColor, padding: EdgeInsets.all(10), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -68,7 +68,7 @@ class _GeneralSettings extends State ], )), Container( - color: Theme.of(context).primaryColor, + color: Theme.of(context).scaffoldBackgroundColor, padding: EdgeInsets.all(10), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -88,7 +88,7 @@ class _GeneralSettings extends State ], )), Container( - color: Theme.of(context).primaryColor, + color: Theme.of(context).scaffoldBackgroundColor, padding: EdgeInsets.all(10), child: AppText( TranslationBase.of(context).blindMode, @@ -96,7 +96,7 @@ class _GeneralSettings extends State ), ), new Container( - color: Theme.of(context).primaryColor, + color: Theme.of(context).scaffoldBackgroundColor, padding: EdgeInsets.all(8.0), child: new Column( mainAxisAlignment: MainAxisAlignment.center, @@ -179,7 +179,7 @@ class _GeneralSettings extends State ) ])), Container( - color: Theme.of(context).primaryColor, + color: Theme.of(context).scaffoldBackgroundColor, padding: EdgeInsets.all(10), child: AppText( TranslationBase.of(context).permissions, @@ -187,7 +187,7 @@ class _GeneralSettings extends State ), ), Container( - color: Theme.of(context).primaryColor, + color: Theme.of(context).scaffoldBackgroundColor, padding: EdgeInsets.all(10), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -206,7 +206,7 @@ class _GeneralSettings extends State ], )), Container( - color: Theme.of(context).primaryColor, + color: Theme.of(context).scaffoldBackgroundColor, padding: EdgeInsets.all(10), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, diff --git a/lib/theme/theme_value.dart b/lib/theme/theme_value.dart index 129174ee..e209081d 100644 --- a/lib/theme/theme_value.dart +++ b/lib/theme/theme_value.dart @@ -35,7 +35,7 @@ defaultTheme({fontName}) { backgroundColor: Color.fromRGBO(255, 255, 255, 1), highlightColor: Colors.grey[100].withOpacity(0.4), splashColor: Colors.transparent, - primaryColor: Color(0xffffffff), + primaryColor: Color(0xff515A5D), buttonColor: Colors.black, toggleableActiveColor: secondaryColor, indicatorColor: secondaryColor, From 0445011e53a5bad6a8ce56fb27b56990eca09249 Mon Sep 17 00:00:00 2001 From: Sultan Khan Date: Mon, 15 Mar 2021 14:32:05 +0300 Subject: [PATCH 12/26] bug fixes --- lib/config/localized_values.dart | 32 +++-- .../ancillary-orders/ancillaryOrders.dart | 2 +- .../ancillaryOrdersDetails.dart | 54 +++++++- .../insurance/insurance_card_screen.dart | 120 +++++++++++------- lib/pages/login/login.dart | 4 +- lib/uitl/translations_delegate_base.dart | 19 ++- 6 files changed, 169 insertions(+), 62 deletions(-) diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index 4cababb4..ca30816c 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -1961,20 +1961,34 @@ const Map localizedValues = { "en": "Your session has timed out, Please try again", "ar": "انتهت مهلة جلسة الخاص بها. يرجى المحاولة مرة أخرى" }, - "ancillary-orders": {"en": "Ancillary Orders", "ar": "الأوامر التبعية"}, + "ancillary-orders": {"en": "Ancillary Orders", "ar": "الأوامر التبعية"}, - "onlineCheckInAgreement": {"en": "The online check-in is for non-life threatening situationCall the red crescent (number) or go to the nearest emergency department if there are:signs of stroke or heart attack history of seizure or syncope there is limb or life threatening injury picture of severe injuries​", - "ar": "تسجيل الذهاب الى الطوارئ عبر الإنترنت هو فقط للحالات  التي لا تهدد الحياة يجب الاتصل بالهلال الأحمر (رقم) أو الذهاب إلى أقرب قسم طوارئ إذا كان هناك علامات السكتة الدماغية أو النوبة القلبية او هناك نوبة تشنج او حالة فقدان الوعي او وجود إصابة تهدد أحد الأطراف او تهدد الحياة او وجود إصابات خطيرة"}, + "onlineCheckInAgreement": { + "en": + "The online check-in is for non-life threatening situationCall the red crescent (number) or go to the nearest emergency department if there are:signs of stroke or heart attack history of seizure or syncope there is limb or life threatening injury picture of severe injuries​", + "ar": + "تسجيل الذهاب الى الطوارئ عبر الإنترنت هو فقط للحالات  التي لا تهدد الحياة يجب الاتصل بالهلال الأحمر (رقم) أو الذهاب إلى أقرب قسم طوارئ إذا كان هناك علامات السكتة الدماغية أو النوبة القلبية او هناك نوبة تشنج او حالة فقدان الوعي او وجود إصابة تهدد أحد الأطراف او تهدد الحياة او وجود إصابات خطيرة" + }, "MRN": {"en": "MRN", "ar": "ایم آر این"}, "appointment-date": {"en": "Appointment Date", "ar": "تقرری کی تاریخ"}, "appointment-no": {"en": "Appointment No", "ar": "تقرری نمبر"}, "insurance-id": {"en": "Insurance ID", "ar": "انشورنس ID"}, "chiefComplaints": {"en": "Chief Complaints", "ar": "الشكوى الرئيسة"}, - "errorChiefComplaints": {"en": "Please Chief Complaints", "ar": "يرجى ادخال الشكوى الرئيسة"}, - "errorExpectedArrivalTimes": {"en": "Please Expected arrival time", "ar": "يرجى ادخال الوقت المتوقع للوصول"}, - "expectedArrivalTime": {"en": "Expected arrival time", "ar": "الوقت المتوقع للوصول"}, - "add-address": { - "en": "Add new address", - "ar": "اضف عنوان جديد" + "errorChiefComplaints": { + "en": "Please Chief Complaints", + "ar": "يرجى ادخال الشكوى الرئيسة" + }, + "errorExpectedArrivalTimes": { + "en": "Please Expected arrival time", + "ar": "يرجى ادخال الوقت المتوقع للوصول" + }, + "expectedArrivalTime": { + "en": "Expected arrival time", + "ar": "الوقت المتوقع للوصول" + }, + "add-address": {"en": "Add new address", "ar": "اضف عنوان جديد"}, + "enter-file": { + "en": "Please enter the mobile number and the medical file number", + "ar": "الرجاء إدخال رقم الجوال ورقم الملف الطبي" } }; diff --git a/lib/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrders.dart b/lib/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrders.dart index b229775a..eccc1309 100644 --- a/lib/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrders.dart +++ b/lib/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrders.dart @@ -103,7 +103,7 @@ class _AnicllaryOrdersState extends State bottom: BorderSide( width: 0.5, ))), - padding: EdgeInsets.all(5), + padding: EdgeInsets.all(15), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ diff --git a/lib/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrdersDetails.dart b/lib/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrdersDetails.dart index 9fb7e7d2..dc0d73d4 100644 --- a/lib/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrdersDetails.dart +++ b/lib/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrdersDetails.dart @@ -6,6 +6,7 @@ import 'package:flutter/material.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; import 'package:diplomaticquarterapp/uitl/date_uitl.dart'; import "package:collection/collection.dart"; +import 'package:diplomaticquarterapp/widgets/text/app_texts_widget.dart'; class AnicllaryOrdersDetails extends StatefulWidget { final dynamic appoNo; @@ -186,11 +187,60 @@ class _AnicllaryOrdersState extends State } Widget getAncillaryDetails(model) { - var newMap = groupBy(model.ancillaryListsDetails[0].ancillaryOrderProcList, + Map newMap = groupBy(model.ancillaryListsDetails[0].ancillaryOrderProcList, (obj) => obj.procedureCategoryName); print(newMap); + return Padding( padding: EdgeInsets.only(top: 10, bottom: 10), - child: Column(children: [])); + child: getHeaderDetails(newMap)); + } + + Widget getHeaderDetails(newMap) { + List list = new List(); + + newMap.forEach((key, value) { + list.add( + Texts( + key, + fontWeight: FontWeight.bold, + ), + ); + list.add(Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [getLabDetails(value)], + )); + }); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: list, + ); + } + + getLabDetails(value) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: value.map((result) { + return Container( + width: MediaQuery.of(context).size.width * .9, + padding: EdgeInsets.all(10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Expanded( + flex: 3, + child: Text(result.procedureName.toString(), + overflow: TextOverflow.ellipsis)), + Expanded(child: AppText(result.companyShare.toString())), + Expanded(child: AppText(result.companyTaxAmount.toString())), + Expanded( + child: AppText( + result.companyShareWithTax.toString(), + )) + ], + )); + }).toList(), + ); } } diff --git a/lib/pages/insurance/insurance_card_screen.dart b/lib/pages/insurance/insurance_card_screen.dart index 42efc179..da66c572 100644 --- a/lib/pages/insurance/insurance_card_screen.dart +++ b/lib/pages/insurance/insurance_card_screen.dart @@ -109,58 +109,92 @@ class _InsuranceCardState extends State { ), Column( crossAxisAlignment: - CrossAxisAlignment.stretch, + CrossAxisAlignment.start, children: [ - Texts( - TranslationBase.of(context).category +": "+ - model.insurance[index] - .subCategoryDesc, - fontSize: 18.5, + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Texts( + TranslationBase.of(context) + .category, + fontSize: 18.5), + Texts( + model.insurance[index] + .subCategoryDesc, + fontSize: 18.5) + ], ), Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, children: [ Texts( - TranslationBase.of(context) - .expirationDate +": "+ - convertDateFormat(model - .insurance[index].cardValidTo), - fontSize: 18.5, - ), - Expanded( - child: Column( - children: [ - model.insurance[index].isActive == true - ? Texts( - TranslationBase.of(context) - .activeInsurence, - color: Colors.green, - fontWeight: FontWeight.w900, - fontSize: 17.9) - : Texts( - TranslationBase.of(context) - .notActive, - color: Colors.red, - fontWeight: FontWeight.w900, - fontSize: 17.9) - ], - ), - ), + TranslationBase.of(context) + .expirationDate, + fontSize: 18.5), + Texts( + convertDateFormat( + model.insurance[index] + .cardValidTo, + ), + fontSize: 18.5), ], ), - Texts( - TranslationBase.of(context) - .patientCard +": "+ - model - .insurance[index].patientCardID, - fontSize: 18.5, + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Texts( + TranslationBase.of(context) + .status + + ": ", + fontSize: 18.5), + model.insurance[index].isActive == + true + ? Texts( + TranslationBase.of(context) + .activeInsurence, + color: Colors.green, + fontWeight: FontWeight.w900, + fontSize: 17.9) + : Texts( + TranslationBase.of(context) + .notActive, + color: Colors.red, + fontWeight: FontWeight.w900, + fontSize: 17.9) + ], ), - Texts( - TranslationBase.of(context) - .policyNumber +" "+ - model.insurance[index] - .insurancePolicyNumber, - fontSize: 18.5, + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Texts( + TranslationBase.of(context) + .patientCard, + fontSize: 18.5), + Texts( + model.insurance[index] + .patientCardID, + fontSize: 18.5) + ], ), + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Texts( + TranslationBase.of(context) + .policyNumber, + fontSize: 18.5, + ), + Texts( + model.insurance[index] + .insurancePolicyNumber, + fontSize: 18.5, + ) + ]), ], ), SizedBox( diff --git a/lib/pages/login/login.dart b/lib/pages/login/login.dart index 6bc99be5..8d655f76 100644 --- a/lib/pages/login/login.dart +++ b/lib/pages/login/login.dart @@ -88,7 +88,9 @@ class _Login extends State { Expanded( flex: 2, child: Texts( - TranslationBase.of(context).enterNationalId, + loginType == 1 + ? TranslationBase.of(context).enterNationalId + : TranslationBase.of(context).enterFile, fontSize: SizeConfig.textMultiplier * 3.5, textAlign: TextAlign.start, )), diff --git a/lib/uitl/translations_delegate_base.dart b/lib/uitl/translations_delegate_base.dart index a9756330..a90f8614 100644 --- a/lib/uitl/translations_delegate_base.dart +++ b/lib/uitl/translations_delegate_base.dart @@ -1573,12 +1573,18 @@ class TranslationBase { String get shippingAddresss => localizedValues["shipping-address"][locale.languageCode]; String get covidAlert => localizedValues["covid-alert"][locale.languageCode]; - String get pharmacyRelogin => localizedValues["pharmacy-relogin"][locale.languageCode]; - String get onlineCheckInAgreement => localizedValues["onlineCheckInAgreement"][locale.languageCode]; - String get chiefComplaints => localizedValues["chiefComplaints"][locale.languageCode]; - String get errorChiefComplaints => localizedValues["errorChiefComplaints"][locale.languageCode]; - String get expectedArrivalTime => localizedValues["expectedArrivalTime"][locale.languageCode]; - String get errorExpectedArrivalTime => localizedValues["errorExpectedArrivalTimes"][locale.languageCode]; + String get pharmacyRelogin => + localizedValues["pharmacy-relogin"][locale.languageCode]; + String get onlineCheckInAgreement => + localizedValues["onlineCheckInAgreement"][locale.languageCode]; + String get chiefComplaints => + localizedValues["chiefComplaints"][locale.languageCode]; + String get errorChiefComplaints => + localizedValues["errorChiefComplaints"][locale.languageCode]; + String get expectedArrivalTime => + localizedValues["expectedArrivalTime"][locale.languageCode]; + String get errorExpectedArrivalTime => + localizedValues["errorExpectedArrivalTimes"][locale.languageCode]; String get anicllaryOrders => localizedValues["ancillary-orders"][locale.languageCode]; String get mrn => localizedValues["MRN"][locale.languageCode]; @@ -1588,6 +1594,7 @@ class TranslationBase { localizedValues["appointment-no"][locale.languageCode]; String get insuranceID => localizedValues["insurance-id"][locale.languageCode]; + String get enterFile => localizedValues["enter-file"][locale.languageCode]; } class TranslationBaseDelegate extends LocalizationsDelegate { From 9bfd725e4f505af90830f3541962da304ad674e4 Mon Sep 17 00:00:00 2001 From: Sultan Khan Date: Mon, 15 Mar 2021 19:08:57 +0300 Subject: [PATCH 13/26] bug fixes --- lib/theme/theme_value.dart | 13 +- lib/uitl/utils.dart | 98 +-- .../data_display/services)contaniner.dart | 3 +- lib/widgets/drawer/app_drawer_widget.dart | 758 +++++++++--------- 4 files changed, 451 insertions(+), 421 deletions(-) diff --git a/lib/theme/theme_value.dart b/lib/theme/theme_value.dart index e209081d..e20d6439 100644 --- a/lib/theme/theme_value.dart +++ b/lib/theme/theme_value.dart @@ -45,9 +45,9 @@ defaultTheme({fontName}) { primaryTextTheme: TextTheme(bodyText2: TextStyle(color: Colors.white)), iconTheme: IconThemeData(), textTheme: TextTheme( - bodyText1: TextStyle(color: Colors.black), - headline1: TextStyle(color: Colors.white), - ), + bodyText1: TextStyle(color: Colors.black), + headline1: TextStyle(color: Colors.white), + headline2: TextStyle(color: Colors.white)), appBarTheme: AppBarTheme( color: Color(0xff515A5D), brightness: Brightness.light, @@ -74,9 +74,9 @@ invertThemes({fontName}) { ), hintColor: Colors.grey[400], textTheme: TextTheme( - bodyText1: TextStyle(color: Colors.white), - headline1: TextStyle(color: Colors.white), - ), + bodyText1: TextStyle(color: Colors.white), + headline1: TextStyle(color: Colors.white), + headline2: TextStyle(color: Colors.white)), disabledColor: Colors.grey[800], errorColor: Color.fromRGBO(235, 80, 60, 1.0), scaffoldBackgroundColor: Color(0xff000000), // Colors.grey[100], @@ -125,6 +125,7 @@ bwThemes({fontName}) { textTheme: TextTheme( bodyText1: TextStyle(color: Colors.red[900]), headline1: TextStyle(color: Colors.red[900]), + headline2: TextStyle(color: Colors.white), bodyText2: TextStyle(color: Colors.red[900]), subtitle1: TextStyle(color: Colors.red[900]), ), diff --git a/lib/uitl/utils.dart b/lib/uitl/utils.dart index c08d68a4..5b3e1c8c 100644 --- a/lib/uitl/utils.dart +++ b/lib/uitl/utils.dart @@ -183,10 +183,9 @@ class Utils { // } } - static getPhoneNumberWithoutZero(String number){ - String newNumber=""; - if(number.startsWith('0')) - { + static getPhoneNumberWithoutZero(String number) { + String newNumber = ""; + if (number.startsWith('0')) { newNumber = number.substring(1); } return newNumber; @@ -202,7 +201,11 @@ class Utils { .hasMatch(email); } - static List myMedicalList({ProjectViewModel projectViewModel, BuildContext context, bool isLogin, count}) { + static List myMedicalList( + {ProjectViewModel projectViewModel, + BuildContext context, + bool isLogin, + count}) { List medical = List(); if (projectViewModel.havePrivilege(5)) { medical.add(InkWell( @@ -406,16 +409,16 @@ class Utils { )); } if (projectViewModel.havePrivilege(20)) - medical.add(InkWell( - onTap: () { - Navigator.push(context, FadePage(page: HomeReportPage())); - }, - child: MedicalProfileItem( - title: TranslationBase.of(context).medical, - imagePath: 'medical_reports_icon.png', - subTitle: TranslationBase.of(context).medicalSubtitle, - ), - )); + medical.add(InkWell( + onTap: () { + Navigator.push(context, FadePage(page: HomeReportPage())); + }, + child: MedicalProfileItem( + title: TranslationBase.of(context).medical, + imagePath: 'medical_reports_icon.png', + subTitle: TranslationBase.of(context).medicalSubtitle, + ), + )); if (projectViewModel.havePrivilege(19)) { medical.add(InkWell( @@ -477,16 +480,16 @@ class Utils { )); } if (projectViewModel.havePrivilege(30)) - medical.add(InkWell( - onTap: () { - Navigator.push(context, FadePage(page: SmartWatchInstructions())); - }, - child: MedicalProfileItem( - title: TranslationBase.of(context).smartWatches, - imagePath: 'smartwatch_icon.png', - subTitle: TranslationBase.of(context).smartWatchesSubtitle, - ), - )); + medical.add(InkWell( + onTap: () { + Navigator.push(context, FadePage(page: SmartWatchInstructions())); + }, + child: MedicalProfileItem( + title: TranslationBase.of(context).smartWatches, + imagePath: 'smartwatch_icon.png', + subTitle: TranslationBase.of(context).smartWatchesSubtitle, + ), + )); if (projectViewModel.havePrivilege(28)) { medical.add(InkWell( @@ -500,25 +503,29 @@ class Utils { ), )); } - if (projectViewModel.havePrivilege(32) || true) { + if (projectViewModel.havePrivilege(32) || true) { medical.add(InkWell( - onTap: () { - userData().then((userData_){ - if (projectViewModel.isLogin && userData_ != null) { - String patientID = userData_.patientID.toString(); - GifLoaderDialogUtils.showMyDialog(context); - projectViewModel.platformBridge().connectHMGInternetWifi(patientID).then((value) => {GifLoaderDialogUtils.hideDialog(context)}); - } else { - AlertDialogBox( - context: context, - confirmMessage: "Please login with your account first to use this feature", - okText: "OK", - okFunction: () { - AlertDialogBox.closeAlertDialog(context); - }).showAlertDialog(context); - } - }); - }, + onTap: () { + userData().then((userData_) { + if (projectViewModel.isLogin && userData_ != null) { + String patientID = userData_.patientID.toString(); + GifLoaderDialogUtils.showMyDialog(context); + projectViewModel + .platformBridge() + .connectHMGInternetWifi(patientID) + .then((value) => {GifLoaderDialogUtils.hideDialog(context)}); + } else { + AlertDialogBox( + context: context, + confirmMessage: + "Please login with your account first to use this feature", + okText: "OK", + okFunction: () { + AlertDialogBox.closeAlertDialog(context); + }).showAlertDialog(context); + } + }); + }, child: MedicalProfileItem( title: TranslationBase.of(context).internet, imagePath: 'insurance_card_icon.png', @@ -546,12 +553,11 @@ class Utils { } Future userData() async { - var userData = AuthenticatedUser.fromJson(await AppSharedPreferences().getObject(MAIN_USER)); + var userData = AuthenticatedUser.fromJson( + await AppSharedPreferences().getObject(MAIN_USER)); return userData; } - - // extension function that use in iterations(list.. etc) to iterate items and get index and item it self extension IndexedIterable on Iterable { Iterable mapIndexed(T Function(E e, int i) f) { diff --git a/lib/widgets/data_display/services)contaniner.dart b/lib/widgets/data_display/services)contaniner.dart index cb0b3774..e435539f 100644 --- a/lib/widgets/data_display/services)contaniner.dart +++ b/lib/widgets/data_display/services)contaniner.dart @@ -15,7 +15,7 @@ class ServicesContainer extends StatelessWidget { height: 60, margin: EdgeInsets.all(8), decoration: BoxDecoration( - color: Theme.of(context).primaryColor, + color: Theme.of(context).textTheme.headline2.color, shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(7), ), @@ -38,6 +38,7 @@ class ServicesContainer extends StatelessWidget { Texts( title, fontSize: 16, + color: Colors.black, ), ], ), diff --git a/lib/widgets/drawer/app_drawer_widget.dart b/lib/widgets/drawer/app_drawer_widget.dart index 8822526c..d5ddf3a9 100644 --- a/lib/widgets/drawer/app_drawer_widget.dart +++ b/lib/widgets/drawer/app_drawer_widget.dart @@ -61,394 +61,416 @@ class _AppDrawerState extends State { @override Widget build(BuildContext context) { projectProvider = Provider.of(context); - return SizedBox( - width: MediaQuery.of(context).size.width * 0.75, - child: Container( - color: Colors.white, - child: Drawer( - child: Column( - children: [ - Expanded( - flex: 4, - child: ListView( - padding: EdgeInsets.zero, - children: [ - Container( - height: SizeConfig.screenHeight * .30, - child: InkWell( - child: DrawerHeader( - child: Column( - children: [ - Container( - child: - Image.asset('assets/images/logo_HMG.png'), - margin: EdgeInsets.all( - SizeConfig.imageSizeMultiplier * 4), - ), - (user != null && projectProvider.isLogin) - ? Padding( - padding: EdgeInsets.all(15), - child: Column( - mainAxisAlignment: - MainAxisAlignment.start, - children: [ - Row( + return Container( + width: MediaQuery.of(context).size.width * 0.75, + color: Theme.of(context).scaffoldBackgroundColor, + child: Container( + // color: Colors.white, + child: Theme( + data: Theme.of(context).copyWith( + canvasColor: Theme.of(context).scaffoldBackgroundColor), + child: Drawer( + child: Column( + children: [ + Expanded( + flex: 4, + child: ListView( + padding: EdgeInsets.zero, + children: [ + Container( + height: SizeConfig.screenHeight * .30, + child: InkWell( + child: DrawerHeader( + child: Column( + children: [ + Container( + child: Image.asset( + 'assets/images/logo_HMG.png'), + margin: EdgeInsets.all( + SizeConfig.imageSizeMultiplier * 4), + ), + (user != null && projectProvider.isLogin) + ? Padding( + padding: EdgeInsets.all(15), + child: Column( + mainAxisAlignment: + MainAxisAlignment.start, children: [ - Padding( - padding: EdgeInsets.only( - right: 5), - child: Icon( - Icons.account_circle, + Row( + children: [ + Padding( + padding: + EdgeInsets.only( + right: 5), + child: Icon( + Icons.account_circle, + color: + Color(0xFF40ACC9), + )), + AppText( + user.firstName + + ' ' + + user.lastName, color: Color(0xFF40ACC9), + ) + ], + ), + Row(children: [ + Padding( + padding: EdgeInsets.only( + left: 30, top: 5), + child: Column( + children: [ + AppText( + TranslationBase.of( + context) + .fileno + + ": " + + user.patientID + .toString(), + color: Color( + 0xFF40ACC9), + fontSize: SizeConfig + .textMultiplier * + 1.5, + ), + AppText( + user.bloodGroup != + null + ? 'Blood Group: ' + + user.bloodGroup + : '', + fontSize: SizeConfig + .textMultiplier * + 1.5, + ), + ], + )) + ]) + ])) + : SizedBox(), + ], + ), + ), + ), + ), + Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + InkWell( + child: DrawerItem( + TranslationBase.of(context).arabicChange, + Icons.translate), + onTap: () { + sharedPref.setBool(IS_ROBOT_INIT, null); + if (projectProvider.isArabic) { + projectProvider.changeLanguage('en'); + } else { + projectProvider.changeLanguage('ar'); + } + }, + ), + (user != null && projectProvider.isLogin) + ? Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + (user.isFamily == null || + user.isFamily == false) && + projectProvider.havePrivilege(2) + ? InkWell( + child: DrawerItem( + TranslationBase.of(context) + .family, + Icons.group, + textColor: Theme.of(context) + .textTheme + .bodyText1 + .color, + iconColor: Theme.of(context) + .textTheme + .bodyText1 + .color, + bottomLine: false, + sideArrow: true, + ), + onTap: () { + Navigator.of(context).pushNamed( + MY_FAMILIY, + ); + }, + ) + : SizedBox(), + FutureBuilder( + future: getFamilyFiles(), // async work + builder: (BuildContext context, + AsyncSnapshot< + GetAllSharedRecordsByStatusResponse> + snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.waiting: + return Padding( + padding: EdgeInsets.all(10), + child: Text('')); + default: + if (snapshot.hasError) + return Padding( + padding: EdgeInsets.all(10), + child: + Text(snapshot.error)); + else + return Container( + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + // <--- left side + color: Colors.grey[200], + width: 1.0, + ), )), - AppText( - user.firstName + - ' ' + - user.lastName, - color: Color(0xFF40ACC9), - ) - ], - ), - Row(children: [ - Padding( - padding: EdgeInsets.only( - left: 30, top: 5), - child: Column( - children: [ - AppText( - TranslationBase.of( - context) - .fileno + - ": " + - user.patientID - .toString(), - color: - Color(0xFF40ACC9), - fontSize: SizeConfig - .textMultiplier * - 1.5, + child: Column( + children: [ + user.isFamily == true + ? Container( + padding: EdgeInsets + .only( + bottom: + 5), + child: InkWell( + onTap: () { + switchUser( + mainUser, + context); + }, + child: Row( + crossAxisAlignment: + CrossAxisAlignment + .start, + children: < + Widget>[ + Expanded( + child: + Icon(Icons.person), + ), + Expanded( + flex: + 7, + child: + Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + AppText(mainUser.firstName + ' ' + mainUser.lastName, color: Theme.of(context).textTheme.bodyText1.color), + AppText( + TranslationBase.of(context).fileno + ": " + mainUser.patientID.toString(), + color: Theme.of(context).textTheme.bodyText1.color, + ), + ])), + ], + ))) + : SizedBox(), + Column( + mainAxisAlignment: + MainAxisAlignment + .start, + mainAxisSize: + MainAxisSize + .min, + children: snapshot + .data + .getAllSharedRecordsByStatusList + .map( + (result) { + return result + .status == + 3 + ? Container( + padding: EdgeInsets.only( + bottom: + 5), + child: InkWell( + onTap: () { + switchUser(result, + context); + }, + child: Row( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Expanded( + child: Icon(Icons.person, color: result.responseID == user.patientID ? Color(0xFF40ACC9) : Colors.black), + ), + Expanded( + flex: 7, + child: Padding( + padding: EdgeInsets.only(left: 5, right: 5), + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + AppText(result.patientName, color: result.responseID == user.patientID ? Color(0xFF40ACC9) : Colors.black), + AppText(TranslationBase.of(context).fileno + ": " + result.iD.toString(), color: result.responseID == user.patientID ? Color(0xFF40ACC9) : Colors.black), + ]))), + ], + ))) + : SizedBox(); + }).toList()) + ], + )); + } + }, + ), + InkWell( + child: Stack( + children: [ + DrawerItem( + TranslationBase.of(context) + .notification, + Icons.notifications, + count: notificationCount != null + ? new Container( + padding: + EdgeInsets.all(4), + margin: EdgeInsets.all(2), + decoration: + new BoxDecoration( + color: Colors.red, + borderRadius: + BorderRadius + .circular(20), ), - AppText( - user.bloodGroup != null - ? 'Blood Group: ' + - user.bloodGroup - : '', - fontSize: SizeConfig - .textMultiplier * - 1.5, + constraints: + BoxConstraints( + minWidth: 20, + minHeight: 20, ), - ], - )) - ]) - ])) - : SizedBox(), - ], - ), - ), - ), - ), - Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - InkWell( - child: DrawerItem( - TranslationBase.of(context).arabicChange, - Icons.translate), - onTap: () { - sharedPref.setBool(IS_ROBOT_INIT, null); - if (projectProvider.isArabic) { - projectProvider.changeLanguage('en'); - } else { - projectProvider.changeLanguage('ar'); - } - }, - ), - (user != null && projectProvider.isLogin) - ? Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - (user.isFamily == null || - user.isFamily == false) && - projectProvider.havePrivilege(2) - ? InkWell( + child: new Text( + notificationCount, + style: new TextStyle( + color: Colors.white, + fontSize: + projectProvider + .isArabic + ? 8 + : 9, + ), + textAlign: + TextAlign.center, + ), + // ), + ) + : SizedBox(), + ), + ], + ), + onTap: () { + //NotificationsPage + Navigator.of(context).pop(); + Navigator.push( + context, + FadePage( + page: NotificationsPage())); + }, + ), + if (projectProvider.havePrivilege(3)) + InkWell( child: DrawerItem( - TranslationBase.of(context).family, - Icons.group, - textColor: Theme.of(context) - .textTheme - .bodyText1 - .color, - iconColor: Theme.of(context) - .textTheme - .bodyText1 - .color, - bottomLine: false, - sideArrow: true, - ), + TranslationBase.of(context) + .appsetting, + Icons.settings_input_composite), onTap: () { Navigator.of(context).pushNamed( - MY_FAMILIY, + SETTINGS, ); }, - ) - : SizedBox(), - FutureBuilder( - future: getFamilyFiles(), // async work - builder: (BuildContext context, - AsyncSnapshot< - GetAllSharedRecordsByStatusResponse> - snapshot) { - switch (snapshot.connectionState) { - case ConnectionState.waiting: - return Padding( - padding: EdgeInsets.all(10), - child: Text('')); - default: - if (snapshot.hasError) - return Padding( - padding: EdgeInsets.all(10), - child: Text(snapshot.error)); - else - return Container( - decoration: BoxDecoration( - border: Border( - bottom: BorderSide( - // <--- left side - color: Colors.grey[200], - width: 1.0, - ), - )), - child: Column( - children: [ - user.isFamily == true - ? Container( - padding: - EdgeInsets.only( - bottom: 5), - child: InkWell( - onTap: () { - switchUser( - mainUser, - context); - }, - child: Row( - crossAxisAlignment: - CrossAxisAlignment - .start, - children: < - Widget>[ - Expanded( - child: Icon( - Icons - .person), - ), - Expanded( - flex: 7, - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - AppText(mainUser.firstName + ' ' + mainUser.lastName), - AppText(TranslationBase.of(context).fileno + ": " + mainUser.patientID.toString()), - ])), - ], - ))) - : SizedBox(), - Column( - mainAxisAlignment: - MainAxisAlignment - .start, - mainAxisSize: - MainAxisSize.min, - children: snapshot.data - .getAllSharedRecordsByStatusList - .map( - (result) { - return result - .status == - 3 - ? Container( - padding: EdgeInsets - .only( - bottom: - 5), - child: InkWell( - onTap: () { - switchUser( - result, - context); - }, - child: Row( - crossAxisAlignment: - CrossAxisAlignment.start, - children: < - Widget>[ - Expanded( - child: - Icon(Icons.person, color: result.responseID == user.patientID ? Color(0xFF40ACC9) : Colors.black), - ), - Expanded( - flex: 7, - child: Padding( - padding: EdgeInsets.only(left: 5, right: 5), - child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - AppText(result.patientName, color: result.responseID == user.patientID ? Color(0xFF40ACC9) : Colors.black), - AppText(TranslationBase.of(context).fileno + ": " + result.iD.toString(), color: result.responseID == user.patientID ? Color(0xFF40ACC9) : Colors.black), - ]))), - ], - ))) - : SizedBox(); - }).toList()) - ], - )); - } - }, - ), - InkWell( - child: Stack( - children: [ - DrawerItem( - TranslationBase.of(context) - .notification, - Icons.notifications, - count: notificationCount != null - ? new Container( - padding: EdgeInsets.all(4), - margin: EdgeInsets.all(2), - decoration: new BoxDecoration( - color: Colors.red, - borderRadius: - BorderRadius.circular( - 20), - ), - constraints: BoxConstraints( - minWidth: 20, - minHeight: 20, - ), - child: new Text( - notificationCount, - style: new TextStyle( - color: Colors.white, - fontSize: projectProvider - .isArabic - ? 8 - : 9, - ), - textAlign: TextAlign.center, - ), - // ), - ) - : SizedBox(), ), - ], - ), - onTap: () { - //NotificationsPage - Navigator.of(context).pop(); - Navigator.push(context, - FadePage(page: NotificationsPage())); - }, - ), - if (projectProvider.havePrivilege(3)) - InkWell( - child: DrawerItem( - TranslationBase.of(context) - .appsetting, - Icons.settings_input_composite), - onTap: () { - Navigator.of(context).pushNamed( - SETTINGS, - ); - }, - ), - InkWell( - child: DrawerItem( - TranslationBase.of(context).rateApp, - Icons.star), - onTap: () { - if (Platform.isIOS) { - launch( - "https://apps.apple.com/sa/app/dr-suliaman-alhabib/id733503978"); - } else { - launch( - "https://play.google.com/store/apps/details?id=com.ejada.hmg&hl=en"); - } - }, - ), - InkWell( + InkWell( + child: DrawerItem( + TranslationBase.of(context).rateApp, + Icons.star), + onTap: () { + if (Platform.isIOS) { + launch( + "https://apps.apple.com/sa/app/dr-suliaman-alhabib/id733503978"); + } else { + launch( + "https://play.google.com/store/apps/details?id=com.ejada.hmg&hl=en"); + } + }, + ), + InkWell( + child: DrawerItem( + TranslationBase.of(context).logout, + Icons.lock_open), + onTap: () { + logout(); + }, + ) + ], + ) + : InkWell( child: DrawerItem( - TranslationBase.of(context).logout, + TranslationBase.of(context) + .loginregister, Icons.lock_open), onTap: () { - logout(); + login(); }, - ) - ], - ) - : InkWell( - child: DrawerItem( - TranslationBase.of(context).loginregister, - Icons.lock_open), - onTap: () { - login(); - }, - ), - // InkWell( - // child: DrawerItem( - // TranslationBase.of(context).appsetting, - // Icons.settings_input_composite), - // onTap: () { - // Navigator.of(context).pushNamed( - // SETTINGS, - // ); - // }, - // ) + ), + // InkWell( + // child: DrawerItem( + // TranslationBase.of(context).appsetting, + // Icons.settings_input_composite), + // onTap: () { + // Navigator.of(context).pushNamed( + // SETTINGS, + // ); + // }, + // ) + ], + )) ], - ) - ], - ), - ), - Expanded( - flex: 1, - child: Column( - children: [ - Container( - child: Align( - alignment: FractionalOffset.bottomCenter, - child: Container( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Column( - children: [ - Text(TranslationBase.of(context).poweredBy), - Image.asset( - 'assets/images/cs_logo_container.png', - width: SizeConfig.imageSizeMultiplier * 30, - ) - ], - ), - Column( - children: [ - Image.asset( - 'assets/images/new-design/vidamobile.png', - width: SizeConfig.imageSizeMultiplier * 25, - ) + ), + ), + Expanded( + flex: 1, + child: Column( + children: [ + Container( + child: Align( + alignment: FractionalOffset.bottomCenter, + child: Container( + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + children: [ + Column( + children: [ + Text(TranslationBase.of(context) + .poweredBy), + Image.asset( + 'assets/images/cs_logo_container.png', + width: + SizeConfig.imageSizeMultiplier * 30, + ) + ], + ), + Column( + children: [ + Image.asset( + 'assets/images/new-design/vidamobile.png', + width: + SizeConfig.imageSizeMultiplier * 25, + ) + ], + ), ], ), - ], + ), ), - ), - ), - ) - ], - ), - ) - ], + ) + ], + ), + ) + ], + ), + ), ), - ), - ), - ); + )); } drawerNavigator(context, routeName) { From 60b1688bb4ff81264f69aeb8c23387d551366782 Mon Sep 17 00:00:00 2001 From: Sultan Khan Date: Tue, 16 Mar 2021 10:40:17 +0300 Subject: [PATCH 14/26] chatbot --- lib/uitl/utils.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/uitl/utils.dart b/lib/uitl/utils.dart index 5b3e1c8c..b4804a21 100644 --- a/lib/uitl/utils.dart +++ b/lib/uitl/utils.dart @@ -36,6 +36,7 @@ import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:url_launcher/url_launcher.dart'; import '../Constants.dart'; import 'app_shared_preferences.dart'; @@ -536,10 +537,9 @@ class Utils { if (projectViewModel.havePrivilege(40)) { medical.add(InkWell( -// onTap: () { -// Navigator.push( -// context, FadePage(page: InsuranceApproval())); -// }, + onTap: () { + launch('whatsapp://send?phone=18885521858&text='); + }, child: MedicalProfileItem( title: TranslationBase.of(context).chatbot, imagePath: 'insurance_approvals_icon.png', From b36e00d2a5f2d126242e28c8f35897e2a7e07be0 Mon Sep 17 00:00:00 2001 From: Mohammad Aljammal Date: Tue, 16 Mar 2021 10:00:47 +0200 Subject: [PATCH 15/26] fix the line chart issues --- .../medical/vital_sign/LineChartCurved.dart | 91 +++++++++++++------ .../LineChartCurvedBloodPressure.dart | 4 +- 2 files changed, 67 insertions(+), 28 deletions(-) diff --git a/lib/pages/medical/vital_sign/LineChartCurved.dart b/lib/pages/medical/vital_sign/LineChartCurved.dart index f2bc3d5f..fe112767 100644 --- a/lib/pages/medical/vital_sign/LineChartCurved.dart +++ b/lib/pages/medical/vital_sign/LineChartCurved.dart @@ -14,10 +14,18 @@ class LineChartCurved extends StatelessWidget { List xAxixs = List(); List yAxixs = List(); + double minY = 0; + double maxY = 0; + + double minX = 0; + double maxX = 0; + double increasingY = 0; + @override Widget build(BuildContext context) { getXaxix(); getYaxix(); + calculateMaxAndMin(); return AspectRatio( aspectRatio: 1.1, child: Container( @@ -70,10 +78,18 @@ class LineChartCurved extends StatelessWidget { } } } + getYaxix() { - int indexess= (timeSeries.length*0.30).toInt(); + // int indexess= (timeSeries.length*0.30).toInt(); + // for (int index = 0; index < timeSeries.length; index++) { + // int mIndex = indexess * index; + // if (mIndex < timeSeries.length) { + // yAxixs.add(timeSeries[mIndex].sales); + // } + // } + for (int index = 0; index < timeSeries.length; index++) { - int mIndex = indexess * index; + int mIndex = indexes * index; if (mIndex < timeSeries.length) { yAxixs.add(timeSeries[mIndex].sales); } @@ -100,7 +116,6 @@ class LineChartCurved extends StatelessWidget { fontSize: 10, ), rotateAngle:-65, - //rotateAngle:-65, margin: 22, getTitles: (value) { if (timeSeries.length < 15) { @@ -128,18 +143,18 @@ class LineChartCurved extends StatelessWidget { fontSize: 10, ), getTitles: (value) { - // if (timeSeries.length < 10) { - // return '${value.toInt()}'; - // } else { - // if (value == getMinY()) - // return '${value.toInt()}'; - // if (value == getMaxY()) - // return '${value.toInt()}'; - // if (yAxixs.contains(value)) { - // return '${value.toInt()}'; - // } - // return ''; - // } + if (timeSeries.length < 15) { + return '${value.toInt()}'; + } else { + if (value == minY) + return '${value.toInt()}'; + if (value == getMaxY()) + return '${value.toInt()}'; + //if (yAxixs.contains(value)) { + return '${value.toInt()}'; + + return ''; + } return '${value.toInt()}'; }, margin: 12, @@ -163,31 +178,55 @@ class LineChartCurved extends StatelessWidget { ), ), ), - minX: 0, - maxX: (timeSeries.length - 1).toDouble(), - maxY: getMaxY()+0.3, - minY: getMinY(), + minX: minX, + maxX: maxX, + maxY: maxY, + minY: minY, lineBarsData: getData(context), ); } + calculateMaxAndMin(){ + getMaxY(); + getMaxX(); + getMin(); + getMinY(); + increasingY = ((maxY-minY)/timeSeries.length - 1)*15; + maxY += increasingY.abs(); + minY -= increasingY.abs(); + } + double getMaxY() { - double max = 0; + maxY = 0; + timeSeries.forEach((element) { + double resultValueDouble = element.sales; + if (resultValueDouble > maxY) maxY = resultValueDouble; + }); + + return maxY.roundToDouble() ; + } + + getMaxX(){ + maxX = (timeSeries.length - 1).toDouble(); + } + + double getMin(){ + minX = 0; timeSeries.forEach((element) { double resultValueDouble = element.sales; - if (resultValueDouble > max) max = resultValueDouble; + if (resultValueDouble < minX) minX = resultValueDouble; }); - return max.roundToDouble() ; + return minX.roundToDouble() ; } double getMinY() { - double min = timeSeries[0].sales; + minY = 0; timeSeries.forEach((element) { double resultValueDouble = element.sales; - if (resultValueDouble < min) min = resultValueDouble; + if (resultValueDouble < minY) minY = resultValueDouble; }); - int value = min.toInt(); + int value = minY.toInt(); return value.toDouble(); } @@ -202,7 +241,7 @@ class LineChartCurved extends StatelessWidget { spots: spots, isCurved: true, colors: [secondaryColor], - barWidth: 5, + barWidth: 3, isStrokeCapRound: true, dotData: FlDotData( show: false, diff --git a/lib/pages/medical/vital_sign/LineChartCurvedBloodPressure.dart b/lib/pages/medical/vital_sign/LineChartCurvedBloodPressure.dart index fa177b1a..605e264a 100644 --- a/lib/pages/medical/vital_sign/LineChartCurvedBloodPressure.dart +++ b/lib/pages/medical/vital_sign/LineChartCurvedBloodPressure.dart @@ -178,8 +178,8 @@ class LineChartCurvedBloodPressure extends StatelessWidget { ), minX: 0, maxX: (timeSeries1.length - 1).toDouble(), - maxY: getMaxY() + 0.3, - minY: getMinY(), + maxY: getMaxY() + 15, + minY: getMinY()-15, lineBarsData: getData(context), ); } From 6f2c947687a4b67122335e0e2d55f39652ba8ff6 Mon Sep 17 00:00:00 2001 From: Zohaib Iqbal Kambrani <> Date: Tue, 16 Mar 2021 12:06:54 +0300 Subject: [PATCH 16/26] Packages And offers.. --- assets/images/svg/robort_svg.svg | 1 + assets/images/svg/success.svg | 67 +++ lib/config/config.dart | 3 +- lib/core/enum/PaymentOptions.dart | 34 ++ lib/core/model/ResponseModel.dart | 7 + .../PackagesCartItemsResponseModel.dart | 6 +- .../PackagesCustomerResponseModel.dart | 218 +++++++- .../responses/order_response_model.dart | 323 ++++++++++++ .../PackagesOffersServices.dart | 71 ++- .../PackagesOffersViewModel.dart | 15 +- lib/main.dart | 7 +- lib/pages/landing/home_page.dart | 29 ++ .../ClinicOfferAndPackagesPage.dart | 36 +- .../CreateCustomerDailogPage.dart | 206 ++++++++ .../OfferAndPackagesCartPage.dart | 40 +- .../packages_offers/OfferAndPackagesPage.dart | 201 ++++---- .../PackageOrderCompletedPage.dart | 146 ++++++ lib/routes.dart | 3 + lib/widgets/AnimatedTextFields.dart | 347 +++++++++++++ lib/widgets/LoadingButton.dart | 465 ++++++++++++++++++ lib/widgets/TextFieldInertiaDirection.java | 343 +++++++++++++ lib/widgets/in_app_browser/InAppBrowser.dart | 53 +- .../offers_packages/PackagesCartItemCard.dart | 2 +- .../offers_packages/PackagesOfferCard.dart | 4 +- lib/widgets/others/app_scaffold_widget.dart | 91 ++-- 25 files changed, 2522 insertions(+), 196 deletions(-) create mode 100644 assets/images/svg/success.svg create mode 100644 lib/core/enum/PaymentOptions.dart create mode 100644 lib/core/model/ResponseModel.dart create mode 100644 lib/core/model/packages_offers/responses/order_response_model.dart create mode 100644 lib/pages/packages_offers/CreateCustomerDailogPage.dart create mode 100644 lib/pages/packages_offers/PackageOrderCompletedPage.dart create mode 100644 lib/widgets/AnimatedTextFields.dart create mode 100644 lib/widgets/LoadingButton.dart create mode 100644 lib/widgets/TextFieldInertiaDirection.java diff --git a/assets/images/svg/robort_svg.svg b/assets/images/svg/robort_svg.svg index 07d3d4b4..8b4875a1 100644 --- a/assets/images/svg/robort_svg.svg +++ b/assets/images/svg/robort_svg.svg @@ -1,3 +1,4 @@ + diff --git a/assets/images/svg/success.svg b/assets/images/svg/success.svg new file mode 100644 index 00000000..343589bd --- /dev/null +++ b/assets/images/svg/success.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/config/config.dart b/lib/config/config.dart index a167e1b5..3c7e1e9a 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -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/'; diff --git a/lib/core/enum/PaymentOptions.dart b/lib/core/enum/PaymentOptions.dart new file mode 100644 index 00000000..bbf43cb2 --- /dev/null +++ b/lib/core/enum/PaymentOptions.dart @@ -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; + } +} diff --git a/lib/core/model/ResponseModel.dart b/lib/core/model/ResponseModel.dart new file mode 100644 index 00000000..f34abf7d --- /dev/null +++ b/lib/core/model/ResponseModel.dart @@ -0,0 +1,7 @@ +class ResponseModel{ + final bool status; + final String error; + final T data; + + ResponseModel({this.status, this.data, this.error}); +} \ No newline at end of file diff --git a/lib/core/model/packages_offers/responses/PackagesCartItemsResponseModel.dart b/lib/core/model/packages_offers/responses/PackagesCartItemsResponseModel.dart index 9514976f..99c8a8b4 100644 --- a/lib/core/model/packages_offers/responses/PackagesCartItemsResponseModel.dart +++ b/lib/core/model/packages_offers/responses/PackagesCartItemsResponseModel.dart @@ -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"]; diff --git a/lib/core/model/packages_offers/responses/PackagesCustomerResponseModel.dart b/lib/core/model/packages_offers/responses/PackagesCustomerResponseModel.dart index 314b0ad3..245973dd 100644 --- a/lib/core/model/packages_offers/responses/PackagesCustomerResponseModel.dart +++ b/lib/core/model/packages_offers/responses/PackagesCustomerResponseModel.dart @@ -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 _shoppingCartItems; + List _shoppingCartItems; dynamic _billingAddress; dynamic _shippingAddress; - List _addresses; + List _addresses; String _customerGuid; dynamic _username; String _email; @@ -24,13 +54,13 @@ class PackagesCustomerResponseModel { String _lastActivityDateUtc; int _registeredInStoreId; bool _subscribedToNewsletter; - List _roleIds; + List _roleIds; int _id; List get shoppingCartItems => _shoppingCartItems; dynamic get billingAddress => _billingAddress; dynamic get shippingAddress => _shippingAddress; - List get addresses => _addresses; + List get addresses => _addresses; String get customerGuid => _customerGuid; dynamic get username => _username; String get email => _email; @@ -59,7 +89,7 @@ class PackagesCustomerResponseModel { List shoppingCartItems, dynamic billingAddress, dynamic shippingAddress, - List addresses, + List 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 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 toJson() { + var map = {}; + 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; + } + } \ No newline at end of file diff --git a/lib/core/model/packages_offers/responses/order_response_model.dart b/lib/core/model/packages_offers/responses/order_response_model.dart new file mode 100644 index 00000000..ed53a765 --- /dev/null +++ b/lib/core/model/packages_offers/responses/order_response_model.dart @@ -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 _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 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 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 toJson() { + var map = {}; + 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; + } + +} diff --git a/lib/core/service/packages_offers/PackagesOffersServices.dart b/lib/core/service/packages_offers/PackagesOffersServices.dart index c0c7bc94..15811b82 100644 --- a/lib/core/service/packages_offers/PackagesOffersServices.dart +++ b/lib/core/service/packages_offers/PackagesOffersServices.dart @@ -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 latestOffersList = List(); List bestSellerList = List(); List bannersList = List(); - List cartItemList = List(); + List cartItemList = List(); + String cartItemCount = ""; PackagesCustomerResponseModel customer; @@ -154,15 +158,15 @@ class OffersAndPackagesServices extends BaseService { // -------------------- // Create Customer // -------------------- - Future 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> cartItems({@required BuildContext context, bool showLoading = true}) async{ + Future> 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> addProductToCart(AddProductToCartRequestModel request, {@required BuildContext context, bool showLoading = true}) async{ Future errorThrow; + ResponseModel 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> getOrderById(int id, {@required BuildContext context, bool showLoading = true}) async{ + Future errorThrow; + ResponseModel 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; } } diff --git a/lib/core/viewModels/packages_offers/PackagesOffersViewModel.dart b/lib/core/viewModels/packages_offers/PackagesOffersViewModel.dart index 83e104dc..1029ed4d 100644 --- a/lib/core/viewModels/packages_offers/PackagesOffersViewModel.dart +++ b/lib/core/viewModels/packages_offers/PackagesOffersViewModel.dart @@ -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(); get categoryList => service.categoryList; get productList => service.categoryList; + } class PackagesViewModel extends BaseViewModel { @@ -22,5 +23,15 @@ class PackagesViewModel extends BaseViewModel { List get latestOffersList => service.latestOffersList; List get bestSellerList => service.bestSellerList; List get bannersList => service.bannersList; - List get cartItemList => service.cartItemList; + List get cartItemList => service.cartItemList; + + + String _cartItemCount = ""; + + String get cartItemCount => _cartItemCount; + + set cartItemCount(String value) { + _cartItemCount = value; + notifyListeners(); + } } diff --git a/lib/main.dart b/lib/main.dart index 05615a68..aaffe3c3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -60,7 +60,6 @@ class MyApp extends StatelessWidget { ], child: Consumer( 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, ), diff --git a/lib/pages/landing/home_page.dart b/lib/pages/landing/home_page.dart index e3156331..94ebbc06 100644 --- a/lib/pages/landing/home_page.dart +++ b/lib/pages/landing/home_page.dart @@ -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 { ), ], ), + + 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), diff --git a/lib/pages/packages_offers/ClinicOfferAndPackagesPage.dart b/lib/pages/packages_offers/ClinicOfferAndPackagesPage.dart index b1e447ef..76688606 100644 --- a/lib/pages/packages_offers/ClinicOfferAndPackagesPage.dart +++ b/lib/pages/packages_offers/ClinicOfferAndPackagesPage.dart @@ -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 { - List get _products => widget.products; +class _ClinicPackagesPageState extends State with AfterLayoutMixin{ + AppScaffold appScaffold; + List 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 { 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 { 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, diff --git a/lib/pages/packages_offers/CreateCustomerDailogPage.dart b/lib/pages/packages_offers/CreateCustomerDailogPage.dart new file mode 100644 index 00000000..4cf5fa5b --- /dev/null +++ b/lib/pages/packages_offers/CreateCustomerDailogPage.dart @@ -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 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 with AfterLayoutMixin, 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( + 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(); + } + +} diff --git a/lib/pages/packages_offers/OfferAndPackagesCartPage.dart b/lib/pages/packages_offers/OfferAndPackagesCartPage.dart index 98f237f6..72a82d0a 100644 --- a/lib/pages/packages_offers/OfferAndPackagesCartPage.dart +++ b/lib/pages/packages_offers/OfferAndPackagesCartPage.dart @@ -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 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 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 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( diff --git a/lib/pages/packages_offers/OfferAndPackagesPage.dart b/lib/pages/packages_offers/OfferAndPackagesPage.dart index 0a83c683..c908cba4 100644 --- a/lib/pages/packages_offers/OfferAndPackagesPage.dart +++ b/lib/pages/packages_offers/OfferAndPackagesPage.dart @@ -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 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( 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); } ); } diff --git a/lib/pages/packages_offers/PackageOrderCompletedPage.dart b/lib/pages/packages_offers/PackageOrderCompletedPage.dart new file mode 100644 index 00000000..c0a7db46 --- /dev/null +++ b/lib/pages/packages_offers/PackageOrderCompletedPage.dart @@ -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( + 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(); + }, + ), + ); + +} diff --git a/lib/routes.dart b/lib/routes.dart index 57452796..51aaccfe 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -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(), }; diff --git a/lib/widgets/AnimatedTextFields.dart b/lib/widgets/AnimatedTextFields.dart new file mode 100644 index 00000000..b4ad5f65 --- /dev/null +++ b/lib/widgets/AnimatedTextFields.dart @@ -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 validator; + final ValueChanged onFieldSubmitted; + final FormFieldSetter onSaved; + final TextFieldInertiaDirection inertiaDirection; + + @override + _AnimatedTextFormFieldState createState() => _AnimatedTextFormFieldState(); +} + +class _AnimatedTextFormFieldState extends State { + Animation scaleAnimation; + Animation sizeAnimation; + Animation suffixIconOpacityAnimation; + + Animation fieldTranslateAnimation; + Animation iconRotationAnimation; + Animation iconTranslateAnimation; + + @override + void initState() { + super.initState(); + + widget.inertiaController?.addStatusListener(handleAnimationStatus); + + final interval = widget.interval; + final loadingController = widget.loadingController; + + if (loadingController != null) { + scaleAnimation = Tween( + begin: 0.0, + end: 1.0, + ).animate(CurvedAnimation( + parent: loadingController, + curve: _getInternalInterval( + 0, .2, interval.begin, interval.end, Curves.easeOutBack), + )); + suffixIconOpacityAnimation = + Tween(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( + begin: 0.0, + end: sign * 15.0, + ).animate(CurvedAnimation( + parent: inertiaController, + curve: Interval(0, .5, curve: Curves.easeOut), + reverseCurve: Curves.easeIn, + )); + iconRotationAnimation = + Tween(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(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( + 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 validator; + final ValueChanged onFieldSubmitted; + final FormFieldSetter onSaved; + final TextFieldInertiaDirection inertiaDirection; + + @override + _AnimatedPasswordTextFormFieldState createState() => + _AnimatedPasswordTextFormFieldState(); +} + +class _AnimatedPasswordTextFormFieldState + extends State { + 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: [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, + ); + } +} \ No newline at end of file diff --git a/lib/widgets/LoadingButton.dart b/lib/widgets/LoadingButton.dart new file mode 100644 index 00000000..8fef5271 --- /dev/null +++ b/lib/widgets/LoadingButton.dart @@ -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 + with SingleTickerProviderStateMixin { + Animation _sizeAnimation; + Animation _textOpacityAnimation; + Animation _buttonOpacityAnimation; + Animation _ringThicknessAnimation; + Animation _ringOpacityAnimation; + Animation _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(begin: 1.0, end: 0.0).animate( + CurvedAnimation( + parent: widget.controller, + curve: Interval(0.0, .25), + ), + ); + + // _colorAnimation + // _width, _sizeAnimation + + _buttonOpacityAnimation = + Tween(begin: 1.0, end: 0.0).animate(CurvedAnimation( + parent: widget.controller, + curve: Threshold(.65), + )); + + _ringThicknessAnimation = + Tween(begin: _loadingCircleRadius, end: _loadingCircleThickness) + .animate(CurvedAnimation( + parent: widget.controller, + curve: Interval(.65, .85), + )); + _ringOpacityAnimation = + Tween(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(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: [ + 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(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), + 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 + with SingleTickerProviderStateMixin { + var _newText = ''; + var _oldText = ''; + var _layoutHeight = 0.0; + final _textKey = GlobalKey(); + + Animation _animation; + AnimationController _controller; + + double get radius => _layoutHeight / 2; + + + @override + void initState() { + super.initState(); + + _controller = AnimationController( + vsync: this, + duration: const Duration(milliseconds: 500), + ); + + _animation = Tween(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: [ + 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; + } +} \ No newline at end of file diff --git a/lib/widgets/TextFieldInertiaDirection.java b/lib/widgets/TextFieldInertiaDirection.java new file mode 100644 index 00000000..627bf406 --- /dev/null +++ b/lib/widgets/TextFieldInertiaDirection.java @@ -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 validator; + final ValueChanged onFieldSubmitted; + final FormFieldSetter onSaved; + final TextFieldInertiaDirection inertiaDirection; + + @override + _AnimatedTextFormFieldState createState() => _AnimatedTextFormFieldState(); +} + +class _AnimatedTextFormFieldState extends State { + Animation scaleAnimation; + Animation sizeAnimation; + Animation suffixIconOpacityAnimation; + + Animation fieldTranslateAnimation; + Animation iconRotationAnimation; + Animation iconTranslateAnimation; + + @override + void initState() { + super.initState(); + + widget.inertiaController?.addStatusListener(handleAnimationStatus); + + final interval = widget.interval; + final loadingController = widget.loadingController; + + if (loadingController != null) { + scaleAnimation = Tween( + begin: 0.0, + end: 1.0, + ).animate(CurvedAnimation( + parent: loadingController, + curve: _getInternalInterval( + 0, .2, interval.begin, interval.end, Curves.easeOutBack), + )); + suffixIconOpacityAnimation = + Tween(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( + begin: 0.0, + end: sign * 15.0, + ).animate(CurvedAnimation( + parent: inertiaController, + curve: Interval(0, .5, curve: Curves.easeOut), + reverseCurve: Curves.easeIn, + )); + iconRotationAnimation = + Tween(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(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( + 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 validator; + final ValueChanged onFieldSubmitted; + final FormFieldSetter onSaved; + final TextFieldInertiaDirection inertiaDirection; + + @override + _AnimatedPasswordTextFormFieldState createState() => + _AnimatedPasswordTextFormFieldState(); +} + +class _AnimatedPasswordTextFormFieldState + extends State { + 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: [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, + ); + } +} \ No newline at end of file diff --git a/lib/widgets/in_app_browser/InAppBrowser.dart b/lib/widgets/in_app_browser/InAppBrowser.dart index 603c5108..5654411c 100644 --- a/lib/widgets/in_app_browser/InAppBrowser.dart +++ b/lib/widgets/in_app_browser/InAppBrowser.dart @@ -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 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 shouldOverrideUrlLoading( - ShouldOverrideUrlLoadingRequest shouldOverrideUrlLoadingRequest) async { - print("\n\n override ${shouldOverrideUrlLoadingRequest.url}\n\n"); + Future 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 generateURL( @@ -311,4 +346,4 @@ class MyChromeSafariBrowser extends ChromeSafariBrowser { void onClosed() { print("ChromeSafari browser closed"); } -} +} \ No newline at end of file diff --git a/lib/widgets/offers_packages/PackagesCartItemCard.dart b/lib/widgets/offers_packages/PackagesCartItemCard.dart index 72ce7475..532c132d 100644 --- a/lib/widgets/offers_packages/PackagesCartItemCard.dart +++ b/lib/widgets/offers_packages/PackagesCartItemCard.dart @@ -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( diff --git a/lib/widgets/offers_packages/PackagesOfferCard.dart b/lib/widgets/offers_packages/PackagesOfferCard.dart index af0341c5..c0a1a22a 100644 --- a/lib/widgets/offers_packages/PackagesOfferCard.dart +++ b/lib/widgets/offers_packages/PackagesOfferCard.dart @@ -30,6 +30,7 @@ class PackagesItemCard extends StatefulWidget { } class PackagesItemCardState extends State { + 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 { child: ClipRRect( borderRadius: BorderRadius.circular(10), child: Utils.loadNetworkImage( - url: - "https://wallpaperaccess.com/full/30103.jpg", + url: imageUrl(), )), )), Text( diff --git a/lib/widgets/others/app_scaffold_widget.dart b/lib/widgets/others/app_scaffold_widget.dart index af61052e..9c9cbcf9 100644 --- a/lib/widgets/others/app_scaffold_widget.dart +++ b/lib/widgets/others/app_scaffold_widget.dart @@ -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(); + 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(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(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(); @@ -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 createState() => AppBarWidgetState(); + + @override + Size get preferredSize => Size(double.maxFinite, 60); +} + +class AppBarWidgetState extends State{ + + 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: [ - (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 r) => false); + (Route 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); } From f9b8191a5ee480c681e58eeaf576dff683d8bc3e Mon Sep 17 00:00:00 2001 From: hussam al-habibeh Date: Tue, 16 Mar 2021 15:21:21 +0200 Subject: [PATCH 17/26] jira bugs --- lib/config/config.dart | 20 +- lib/core/service/client/base_app_client.dart | 46 ++- lib/pages/insurance/insurance_page.dart | 291 +++++++++--------- .../insurance/insurance_update_screen.dart | 10 +- 4 files changed, 176 insertions(+), 191 deletions(-) diff --git a/lib/config/config.dart b/lib/config/config.dart index 0f8df420..c8ad92ef 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -95,9 +95,12 @@ const GET_NEAREST_HOSPITAL = 'Services/Patients.svc/REST/Patient_GetProjectAvgERWaitingTime'; ///ED Online -const ER_GET_VISUAL_TRIAGE_QUESTIONS = "services/Doctors.svc/REST/ER_GetVisualTriageQuestions"; -const ER_SAVE_TRIAGE_INFORMATION = "services/Doctors.svc/REST/ER_SaveTriageInformation"; -const ER_GetPatientPaymentInformationForERClinic = "services/Doctors.svc/REST/ER_GetPatientPaymentInformationForERClinic"; +const ER_GET_VISUAL_TRIAGE_QUESTIONS = + "services/Doctors.svc/REST/ER_GetVisualTriageQuestions"; +const ER_SAVE_TRIAGE_INFORMATION = + "services/Doctors.svc/REST/ER_SaveTriageInformation"; +const ER_GetPatientPaymentInformationForERClinic = + "services/Doctors.svc/REST/ER_GetPatientPaymentInformationForERClinic"; ///Er Nearest const GET_AMBULANCE_REQUEST = @@ -312,7 +315,7 @@ var DEVICE_TOKEN = ""; var IS_VOICE_COMMAND_CLOSED = false; var IS_TEXT_COMPLETED = false; var DeviceTypeID = Platform.isIOS ? 1 : 2; -const LANGUAGE_ID = 1; +const LANGUAGE_ID = 2; const GET_PHARMCY_ITEMS = "Services/Lists.svc/REST/GetPharmcyItems_Region"; const GET_PHARMACY_LIST = "Services/Patients.svc/REST/GetPharmcyList"; const GET_PAtIENTS_INSURANCE = @@ -534,12 +537,9 @@ const GET_SPECIFICATION = "productspecification/"; const GET_BRAND_ITEMS = "products"; // External API -const ADD_ADDRESS_INFO = - "addcustomeraddress"; -const GET_CUSTOMER_ADDRESSES = - "Customers/"; -const GET_CUSTOMER_INFO = - "VerifyCustomer"; +const ADD_ADDRESS_INFO = "addcustomeraddress"; +const GET_CUSTOMER_ADDRESSES = "Customers/"; +const GET_CUSTOMER_INFO = "VerifyCustomer"; //Pharmacy diff --git a/lib/core/service/client/base_app_client.dart b/lib/core/service/client/base_app_client.dart index 1d5b55aa..a647c1c0 100644 --- a/lib/core/service/client/base_app_client.dart +++ b/lib/core/service/client/base_app_client.dart @@ -216,11 +216,10 @@ class BaseAppClient { postPharmacy(String endPoint, {Map body, - Function(dynamic response, int statusCode) onSuccess, - Function(String error, int statusCode) onFailure, - bool isAllowAny = false, - bool isExternal = false}) async { - + Function(dynamic response, int statusCode) onSuccess, + Function(String error, int statusCode) onFailure, + bool isAllowAny = false, + bool isExternal = false}) async { var token = await sharedPref.getString(PHARMACY_AUTORZIE_TOKEN); var user = await sharedPref.getObject(USER_PROFILE); String url; @@ -246,12 +245,12 @@ class BaseAppClient { if (!isExternal) { String token = await sharedPref.getString(TOKEN); var languageID = - await sharedPref.getStringWithDefaultValue(APP_LANGUAGE, 'ar'); + await sharedPref.getStringWithDefaultValue(APP_LANGUAGE, 'ar'); if (body.containsKey('SetupID')) { body['SetupID'] = body.containsKey('SetupID') ? body['SetupID'] != null - ? body['SetupID'] - : SETUP_ID + ? body['SetupID'] + : SETUP_ID : SETUP_ID; } @@ -263,17 +262,17 @@ class BaseAppClient { body['generalid'] = GENERAL_ID; body['PatientOutSA'] = body.containsKey('PatientOutSA') ? body['PatientOutSA'] != null - ? body['PatientOutSA'] - : PATIENT_OUT_SA + ? body['PatientOutSA'] + : PATIENT_OUT_SA : PATIENT_OUT_SA; if (body.containsKey('isDentalAllowedBackend')) { body['isDentalAllowedBackend'] = - body.containsKey('isDentalAllowedBackend') - ? body['isDentalAllowedBackend'] != null - ? body['isDentalAllowedBackend'] - : IS_DENTAL_ALLOWED_BACKEND - : IS_DENTAL_ALLOWED_BACKEND; + body.containsKey('isDentalAllowedBackend') + ? body['isDentalAllowedBackend'] != null + ? body['isDentalAllowedBackend'] + : IS_DENTAL_ALLOWED_BACKEND + : IS_DENTAL_ALLOWED_BACKEND; } body['DeviceTypeID'] = DeviceTypeID; @@ -281,18 +280,18 @@ class BaseAppClient { if (!body.containsKey('IsPublicRequest')) { body['PatientType'] = body.containsKey('PatientType') ? body['PatientType'] != null - ? body['PatientType'] - : user['PatientType'] != null - ? user['PatientType'] - : PATIENT_TYPE + ? body['PatientType'] + : user['PatientType'] != null + ? user['PatientType'] + : PATIENT_TYPE : PATIENT_TYPE; body['PatientTypeID'] = body.containsKey('PatientTypeID') ? body['PatientTypeID'] != null - ? body['PatientTypeID'] - : user['PatientType'] != null - ? user['PatientType'] - : PATIENT_TYPE_ID + ? body['PatientTypeID'] + : user['PatientType'] != null + ? user['PatientType'] + : PATIENT_TYPE_ID : PATIENT_TYPE_ID; if (user != null) { body['TokenID'] = token; @@ -587,7 +586,6 @@ class BaseAppClient { return params; } - pharmacyPost(String endPoint, {Map body, Function(dynamic response, int statusCode) onSuccess, diff --git a/lib/pages/insurance/insurance_page.dart b/lib/pages/insurance/insurance_page.dart index f938d9e5..a391f554 100644 --- a/lib/pages/insurance/insurance_page.dart +++ b/lib/pages/insurance/insurance_page.dart @@ -16,7 +16,7 @@ class InsurancePage extends StatelessWidget { final InsuranceViewModel model; InsuranceCardService _insuranceCardService = locator(); - InsurancePage({Key key, this.model}) : super(key: key); + InsurancePage({Key key, this.model}) : super(key: key); @override Widget build(BuildContext context) { return SingleChildScrollView( @@ -31,24 +31,20 @@ class InsurancePage extends StatelessWidget { width: MediaQuery.of(context).size.width, padding: EdgeInsets.all(10.0), child: Row( - crossAxisAlignment: - CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.max, children: [ if (model.user != null) Expanded( flex: 3, child: Container( - margin: EdgeInsets.only( - top: 2.0, - left: 10.0, - right: 20.0), + margin: + EdgeInsets.only(top: 2.0, left: 10.0, right: 20.0), child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, children: [ Texts( - model.user.firstName ?? '' + " " + model.user.lastName ?? '', + model.user.firstName + " " + model.user.lastName, fontSize: 14, color: Colors.black, fontWeight: FontWeight.w500, @@ -57,11 +53,9 @@ class InsurancePage extends StatelessWidget { height: 8, ), Texts( - TranslationBase.of(context) - .fileno + + TranslationBase.of(context).fileno + ": " + - model.user.patientID - .toString(), + model.user.patientID.toString(), fontSize: 14, color: Colors.black, fontWeight: FontWeight.w500, @@ -78,9 +72,7 @@ class InsurancePage extends StatelessWidget { children: [ Container( child: SecondaryButton( - label: TranslationBase.of( - context) - .fetchData, + label: TranslationBase.of(context).fetchData, small: true, textColor: Colors.white, onTap: () { @@ -88,15 +80,12 @@ class InsurancePage extends StatelessWidget { setupID: '010266', projectID: 15, patientIdentificationID: - model.user - .patientIdentificationNo, - patientID: model - .user.patientID, - name: model.user - .firstName + + model.user.patientIdentificationNo, + patientID: model.user.patientID, + name: model.user.firstName + " " + - model - .user.lastName,context: context); + model.user.lastName, + context: context); }, ), ), @@ -107,122 +96,115 @@ class InsurancePage extends StatelessWidget { ], ), ), - if(model.getAllSharedRecordsByStatusResponse.getAllSharedRecordsByStatusList != null ?? false) - ...List.generate(model.getAllSharedRecordsByStatusResponse.getAllSharedRecordsByStatusList.length, (index) => - model.getAllSharedRecordsByStatusResponse.getAllSharedRecordsByStatusList[index].status == 3 - ? Container( - margin: EdgeInsets.all(10.0), - child: Card( - margin: EdgeInsets.fromLTRB( - 8.0, 16.0, 8.0, 8.0), - color: Colors.white, - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(10), - ), - child: Container( - width: MediaQuery.of(context).size.width, - padding: EdgeInsets.all(10.0), - child: Row( - crossAxisAlignment: - CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.max, - children: [ - Expanded( - flex: 3, - child: Container( - margin: EdgeInsets.only( - top: 2.0, - left: 10.0, - right: 20.0), - child: Column( - crossAxisAlignment: - CrossAxisAlignment - .start, - children: [ - Texts( - model - .getAllSharedRecordsByStatusResponse - .getAllSharedRecordsByStatusList[ - index] - .patientName, - fontSize: 14, - color: Colors.black, - fontWeight: - FontWeight.w500, - ), - SizedBox( - height: 8, - ), - Texts( - TranslationBase.of( - context) - .fileno + - ": " + - model - .getAllSharedRecordsByStatusResponse - .getAllSharedRecordsByStatusList[ - index] - .patientID - .toString(), - fontSize: 14, - color: Colors.black, - fontWeight: - FontWeight.w500, - ) - ], - ), - ), - ), - Expanded( - flex: 2, - child: Container( - margin: - EdgeInsets.only(top: 2.0), - child: Column( - children: [ - Container( - child: SecondaryButton( - label: TranslationBase - .of(context) - .fetchData, - small: true, - textColor: - Colors.white, - onTap: () { - getDetails( - projectID: 15, - patientIdentificationID: model - .getAllSharedRecordsByStatusResponse - .getAllSharedRecordsByStatusList[ - index] - .patientIdenficationNumber, - setupID: - '010266', - patientID: model - .getAllSharedRecordsByStatusResponse - .getAllSharedRecordsByStatusList[ - index] - .responseID, - name: model - .getAllSharedRecordsByStatusResponse - .getAllSharedRecordsByStatusList[ - index].patientName,context: context); - }, - ), + if (model.getAllSharedRecordsByStatusResponse + .getAllSharedRecordsByStatusList != + null ?? + false) + ...List.generate( + model.getAllSharedRecordsByStatusResponse + .getAllSharedRecordsByStatusList.length, + (index) => model.getAllSharedRecordsByStatusResponse + .getAllSharedRecordsByStatusList[index].status == + 3 + ? Container( + margin: EdgeInsets.all(10.0), + child: Card( + margin: EdgeInsets.fromLTRB(8.0, 16.0, 8.0, 8.0), + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + child: Container( + width: MediaQuery.of(context).size.width, + padding: EdgeInsets.all(10.0), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + flex: 3, + child: Container( + margin: EdgeInsets.only( + top: 2.0, left: 10.0, right: 20.0), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Texts( + model + .getAllSharedRecordsByStatusResponse + .getAllSharedRecordsByStatusList[ + index] + .patientName, + fontSize: 14, + color: Colors.black, + fontWeight: FontWeight.w500, + ), + SizedBox( + height: 8, + ), + Texts( + TranslationBase.of(context).fileno + + ": " + + model + .getAllSharedRecordsByStatusResponse + .getAllSharedRecordsByStatusList[ + index] + .patientID + .toString(), + fontSize: 14, + color: Colors.black, + fontWeight: FontWeight.w500, + ) + ], + ), + ), + ), + Expanded( + flex: 2, + child: Container( + margin: EdgeInsets.only(top: 2.0), + child: Column( + children: [ + Container( + child: SecondaryButton( + label: TranslationBase.of(context) + .fetchData, + small: true, + textColor: Colors.white, + onTap: () { + getDetails( + projectID: 15, + patientIdentificationID: model + .getAllSharedRecordsByStatusResponse + .getAllSharedRecordsByStatusList[ + index] + .patientIdenficationNumber, + setupID: '010266', + patientID: model + .getAllSharedRecordsByStatusResponse + .getAllSharedRecordsByStatusList[ + index] + .responseID, + name: model + .getAllSharedRecordsByStatusResponse + .getAllSharedRecordsByStatusList[ + index] + .patientName, + context: context); + }, + ), + ), + ], + ), + ), + ) + ], ), - ], + ), ), - ), - ) - ], - ), - ), - ), - ) - : Container() - ), - + ) + : Container()), ], ), ); @@ -230,29 +212,32 @@ class InsurancePage extends StatelessWidget { getDetails( {String setupID, - int projectID, - String patientIdentificationID, - int patientID, - String name,BuildContext context}) { + int projectID, + String patientIdentificationID, + int patientID, + String name, + BuildContext context}) { GifLoaderDialogUtils.showMyDialog(context); _insuranceCardService .getPatientInsuranceDetails( - setupID: setupID, - projectID: projectID, - patientID: patientID, - patientIdentificationID: patientIdentificationID) + setupID: setupID, + projectID: projectID, + patientID: patientID, + patientIdentificationID: patientIdentificationID) .then((value) { GifLoaderDialogUtils.hideDialog(context); - if (!_insuranceCardService.hasError && _insuranceCardService.isHaveInsuranceCard) { + if (!_insuranceCardService.hasError && + _insuranceCardService.isHaveInsuranceCard) { Navigator.push( context, FadePage( page: InsuranceCardUpdateDetails( - insuranceCardDetailsModel: _insuranceCardService.insuranceCardDetailsList, - patientID: patientID, - patientIdentificationID: patientIdentificationID, - name: name, - ))); + insuranceCardDetailsModel: + _insuranceCardService.insuranceCardDetailsList, + patientID: patientID, + patientIdentificationID: patientIdentificationID, + name: name, + ))); } else { AppToast.showErrorToast(message: _insuranceCardService.error); } diff --git a/lib/pages/insurance/insurance_update_screen.dart b/lib/pages/insurance/insurance_update_screen.dart index 36b424a8..6c3ee61c 100644 --- a/lib/pages/insurance/insurance_update_screen.dart +++ b/lib/pages/insurance/insurance_update_screen.dart @@ -32,7 +32,11 @@ class _InsuranceUpdateState extends State super.initState(); _tabController = TabController(length: 2, vsync: this); - imagesInfo.add(ImagesInfo(imageEn: 'https://hmgwebservices.com/Images/MobileApp/imges-info/insurance-card/en/0.png',imageAr: 'https://hmgwebservices.com/Images/MobileApp/imges-info/insurance-card/ar/0.png')); + imagesInfo.add(ImagesInfo( + imageEn: + 'https://hmgwebservices.com/Images/MobileApp/imges-info/insurance-card/en/0.png', + imageAr: + 'https://hmgwebservices.com/Images/MobileApp/imges-info/insurance-card/ar/0.png')); } void dispose() { @@ -111,7 +115,7 @@ class _InsuranceUpdateState extends State physics: BouncingScrollPhysics(), controller: _tabController, children: [ - InsurancePage(model:model), + InsurancePage(model: model), Container( child: ListView.builder( itemCount: model.insuranceUpdate == null @@ -227,6 +231,4 @@ class _InsuranceUpdateState extends State ), ); } - - } From a6ec7326b23698d67abb6f634865181787882c95 Mon Sep 17 00:00:00 2001 From: hussam al-habibeh Date: Tue, 16 Mar 2021 15:37:10 +0200 Subject: [PATCH 18/26] jira bugs --- lib/pages/vaccine/my_vaccines_screen.dart | 37 ++++++++++++----------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/lib/pages/vaccine/my_vaccines_screen.dart b/lib/pages/vaccine/my_vaccines_screen.dart index 169e5cd5..fb723a1f 100644 --- a/lib/pages/vaccine/my_vaccines_screen.dart +++ b/lib/pages/vaccine/my_vaccines_screen.dart @@ -169,29 +169,30 @@ class _MyVaccinesState extends State { width: double.infinity, // height: 80.0, child: Button( + disabled: true, label: TranslationBase.of(context).checkVaccineAvailability, backgroundColor: Color(0xff9EA3A4), - onTap: () => - Navigator.push(context, FadePage(page: MyVaccinesItemPage())), + onTap: () => Navigator.push( + context, FadePage(page: MyVaccinesItemPage())), ), ), - if(projectViewModel.havePrivilege(27)) - Container( - width: double.infinity, - // height: 80.0, - child: SecondaryButton( - label: TranslationBase.of(context).sendEmail, - color: Color(0xffF62426), - textColor: Colors.white, - disabled: model.vaccineList.length == 0, - loading: model.state == ViewState.BusyLocal, - onTap: () async { - model.sendEmail( - message: - TranslationBase.of(context).emailSentSuccessfully); - }, + if (projectViewModel.havePrivilege(27)) + Container( + width: double.infinity, + // height: 80.0, + child: SecondaryButton( + label: TranslationBase.of(context).sendEmail, + color: Color(0xffF62426), + textColor: Colors.white, + disabled: model.vaccineList.length == 0, + loading: model.state == ViewState.BusyLocal, + onTap: () async { + model.sendEmail( + message: TranslationBase.of(context) + .emailSentSuccessfully); + }, + ), ), - ), ], ), ), From 7bdf31000fdd5bedf9197a89103c5c1a4b69586c Mon Sep 17 00:00:00 2001 From: Elham Rababah Date: Wed, 17 Mar 2021 11:35:47 +0200 Subject: [PATCH 19/26] PAP-356: fix chart design --- .../medical/LabResult/FlowChartPage.dart | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/widgets/data_display/medical/LabResult/FlowChartPage.dart b/lib/widgets/data_display/medical/LabResult/FlowChartPage.dart index fde78169..2cc9acd6 100644 --- a/lib/widgets/data_display/medical/LabResult/FlowChartPage.dart +++ b/lib/widgets/data_display/medical/LabResult/FlowChartPage.dart @@ -23,18 +23,21 @@ class FlowChartPage extends StatelessWidget { appBarTitle: filterName, baseViewModel: model, body: SingleChildScrollView( - child: model.labOrdersResultsList.isNotEmpty + child: model. labOrdersResultsList.isNotEmpty ? Container( child: LabResultChartAndDetails( name: filterName, labResult: model.labOrdersResultsList, ), ) - : Container( - child: Center( - child: Texts('no Data'), + : Center( + child: Container( + padding: EdgeInsets.only(top: MediaQuery.of(context).size.height *0.42), + child: Center( + child: Texts('No Data'), + ), ), - ), + ), ), ), ); From 7c1fd8043b5528ecfb2c1674ccb6702560c1cb09 Mon Sep 17 00:00:00 2001 From: Mohammad Aljammal Date: Wed, 17 Mar 2021 12:51:01 +0200 Subject: [PATCH 20/26] fix chart and eye and balance --- lib/config/config.dart | 12 +- .../customer_addresses_service.dart | 7 +- lib/core/service/client/base_app_client.dart | 18 +- lib/core/service/medical/EyeService.dart | 50 +++++ .../service/medical/radiology_service.dart | 2 +- .../add_new_address_Request_Model.dart | 4 +- .../home_health_care_view_model.dart | 12 +- lib/core/viewModels/medical/EyeViewModel.dart | 30 +++ .../NewHomeHealthCare/location_page.dart | 3 +- .../medical/balance/advance_payment_page.dart | 2 +- .../medical/balance/my_balance_page.dart | 4 +- lib/pages/medical/eye/ClassesPage.dart | 68 +++++- lib/pages/medical/eye/ContactLensPage.dart | 205 +++++++++++------- lib/pages/medical/eye/EyeHomePage.dart | 15 +- .../PrescriptionIDeliveryAddressPage.dart | 47 +++- .../medical/reports/report_home_page.dart | 8 +- lib/pages/medical/reports/reports_page.dart | 58 +++-- .../LineChartCurvedBloodPressure.dart | 3 +- lib/pages/paymentService/payment_service.dart | 2 +- 19 files changed, 388 insertions(+), 162 deletions(-) diff --git a/lib/config/config.dart b/lib/config/config.dart index 0f8df420..6902c47d 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -14,12 +14,12 @@ const BASE_URL = 'https://uat.hmgwebservices.com/'; // const BASE_URL = 'https://hmgwebservices.com/'; // Pharmacy UAT URLs -// const BASE_PHARMACY_URL = 'https://uat.hmgwebservices.com/epharmacy/api/'; -// const PHARMACY_BASE_URL = 'https://uat.hmgwebservices.com/epharmacy/api/'; +const BASE_PHARMACY_URL = 'https://uat.hmgwebservices.com/epharmacy/api/'; +const PHARMACY_BASE_URL = 'https://uat.hmgwebservices.com/epharmacy/api/'; // Pharmacy Production URLs -const BASE_PHARMACY_URL = 'https://mdlaboratories.com/exacartapi/api/'; -const PHARMACY_BASE_URL = 'https://mdlaboratories.com/exacartapi/api/'; +// const BASE_PHARMACY_URL = 'https://mdlaboratories.com/exacartapi/api/'; +// const PHARMACY_BASE_URL = 'https://mdlaboratories.com/exacartapi/api/'; const PING_SERVICE = 'Services/Weather.svc/REST/CheckConnectivity'; @@ -210,6 +210,10 @@ const GET_PATIENT_SHARE = const GET_PATIENT_APPOINTMENT_HISTORY = "Services/Doctors.svc/REST/PateintHasAppoimentHistory"; +const SEND_REPORT_EYE_EMAIL = "Services/Notifications.svc/REST/SendGlassesPrescriptionEmail"; + +const SEND_CONTACT_LENS_PRESCRIPTION_EMAIL = "Services/Notifications.svc/REST/SendContactLensPrescriptionEmail"; + //URL to get patient appointment curfew history const GET_PATIENT_APPOINTMENT_CURFEW_HISTORY = "Services/Doctors.svc/REST/AppoimentHistoryForCurfew"; diff --git a/lib/core/service/AlHabibMedicalService/customer_addresses_service.dart b/lib/core/service/AlHabibMedicalService/customer_addresses_service.dart index 34fa4bbb..ea5d03ca 100644 --- a/lib/core/service/AlHabibMedicalService/customer_addresses_service.dart +++ b/lib/core/service/AlHabibMedicalService/customer_addresses_service.dart @@ -1,7 +1,9 @@ import 'package:diplomaticquarterapp/config/config.dart'; import 'package:diplomaticquarterapp/core/viewModels/AlHabibMedicalService/add_new_address_Request_Model.dart'; +import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/pharmacy_module_view_model.dart'; import 'package:intl/intl.dart'; +import '../../../locator.dart'; import '../base_service.dart'; class CustomerAddressesService extends BaseService { @@ -9,6 +11,7 @@ class CustomerAddressesService extends BaseService { List addressesList = List(); CustomerInfo customerInfo; + Future addAddressInfo({ AddNewAddressRequestModel addNewAddressRequestModel }) async { @@ -25,7 +28,7 @@ class CustomerAddressesService extends BaseService { var date = f.format(DateTime.now().toUtc()) + " GMT"; addNewAddressRequestModel.customer.addresses[0].createdOnUtc = date; hasError = false; - await baseAppClient.post(BASE_PHARMACY_URL+ADD_ADDRESS_INFO, + await baseAppClient.post(ADD_CUSTOMER_ADDRESS, onSuccess: (dynamic response, int statusCode) { addressesList.clear(); response["customers"][0]["addresses"].forEach((data) { @@ -35,7 +38,7 @@ class CustomerAddressesService extends BaseService { }, onFailure: (String error, int statusCode) { hasError = true; super.error = error; - }, body: addNewAddressRequestModel.toJson(), isExternal: true, isAllowAny: true); + }, body: addNewAddressRequestModel.toJson(), isAllowAny: true); } Future getCustomerAddresses() async { diff --git a/lib/core/service/client/base_app_client.dart b/lib/core/service/client/base_app_client.dart index 1d5b55aa..4be9325f 100644 --- a/lib/core/service/client/base_app_client.dart +++ b/lib/core/service/client/base_app_client.dart @@ -115,7 +115,9 @@ class BaseAppClient { 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': pharmacyToken, - 'Mobilenumber': user['MobileNumber'].toString(), + 'Mobilenumber': user != null + ? Utils.getPhoneNumberWithoutZero(user['MobileNumber'].toString()) + : "", 'Statictoken': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9', 'Username': user['PatientID'].toString(), }; @@ -238,7 +240,7 @@ class BaseAppClient { 'Accept': 'application/json', 'Authorization': token ?? '', 'Mobilenumber': user != null - ? getPhoneNumberWithoutZero(user['MobileNumber'].toString()) + ? Utils.getPhoneNumberWithoutZero(user['MobileNumber'].toString()) : "", 'Statictoken': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9', 'Username': user != null ? user['PatientID'].toString() : "", @@ -478,7 +480,7 @@ class BaseAppClient { 'Accept': 'application/json', 'Authorization': token ?? '', 'Mobilenumber': user != null - ? getPhoneNumberWithoutZero(user['MobileNumber'].toString()) + ? Utils.getPhoneNumberWithoutZero(user['MobileNumber'].toString()) : "", 'Statictoken': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9', 'Username': user != null ? user['PatientID'].toString() : "", @@ -504,13 +506,7 @@ class BaseAppClient { } } - getPhoneNumberWithoutZero(String number) { - String newNumber = number; - if (number.startsWith('0')) { - newNumber = number.substring(1); - } - return newNumber; - } + simpleGet(String fullUrl, {Function(dynamic response, int statusCode) onSuccess, @@ -680,7 +676,7 @@ class BaseAppClient { 'Accept': 'application/json', 'Authorization': token ?? '', 'Mobilenumber': user != null - ? getPhoneNumberWithoutZero(user['MobileNumber'].toString()) + ? Utils.getPhoneNumberWithoutZero(user['MobileNumber'].toString()) : "", 'Statictoken': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9', 'Username': user != null ? user['PatientID'].toString() : "", diff --git a/lib/core/service/medical/EyeService.dart b/lib/core/service/medical/EyeService.dart index 879acbbf..937f89e3 100644 --- a/lib/core/service/medical/EyeService.dart +++ b/lib/core/service/medical/EyeService.dart @@ -1,6 +1,7 @@ import 'package:diplomaticquarterapp/config/config.dart'; import 'package:diplomaticquarterapp/core/model/eye/AppoimentAllHistoryResult.dart'; import 'package:diplomaticquarterapp/core/service/base_service.dart'; +import 'package:diplomaticquarterapp/uitl/utils.dart'; class EyeService extends BaseService { List appoimentAllHistoryResultList = List(); @@ -23,4 +24,53 @@ class EyeService extends BaseService { super.error = error; }, body: body); } + + sendGlassesPrescriptionEmail({int appointmentNo,String projectName,int projectID}) async { + hasError = false; + super.error = ""; + Map body = Map(); + body['isDentalAllowedBackend'] = false; + body['PatientIditificationNum'] = user.patientIdentificationNo; + body['PatientName'] = user.firstName+" "+user.lastName; + body['To'] = user.emailAddress; + body['SetupID'] = user.setupID; + body['DateofBirth'] = user.dateofBirth; + body['ProjectID'] = projectID; + body['AppointmentNo'] = appointmentNo; + body['ProjectName'] = projectName; + body['PatientID'] = user.patientID; + body['PatientMobileNumber'] = Utils.getPhoneNumberWithoutZero(user.mobileNumber); + await baseAppClient.post(SEND_REPORT_EYE_EMAIL, + onSuccess: (response, statusCode) async { + + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: body); + } + + sendContactLensPrescriptionEmail({int appointmentNo,String projectName,int projectID}) async { + hasError = false; + super.error = ""; + Map body = Map(); + body['isDentalAllowedBackend'] = false; + body['AppointmentNo'] = appointmentNo; + body['PatientIditificationNum'] = user.patientIdentificationNo; + body['PatientName'] = user.firstName+" "+user.lastName; + body['To'] = user.emailAddress; + body['SetupID'] = user.setupID; + body['DateofBirth'] = user.dateofBirth; + body['ProjectID'] = projectID; + body['AppointmentNo'] = appointmentNo; + body['ProjectName'] = projectName; + body['PatientID'] = user.patientID; + body['PatientMobileNumber'] = Utils.getPhoneNumberWithoutZero(user.mobileNumber); + await baseAppClient.post(SEND_CONTACT_LENS_PRESCRIPTION_EMAIL, + onSuccess: (response, statusCode) async { + + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, body: body); + } } diff --git a/lib/core/service/medical/radiology_service.dart b/lib/core/service/medical/radiology_service.dart index 965fa752..b0b96e71 100644 --- a/lib/core/service/medical/radiology_service.dart +++ b/lib/core/service/medical/radiology_service.dart @@ -11,7 +11,7 @@ class RadiologyService extends BaseService { hasError = false; final Map body = new Map(); body['InvoiceNo'] = invoiceNo; - body['LineItemNo'] = lineItem; + body['LineIt emNo'] = lineItem; body['ProjectID'] = projectId; await baseAppClient.post(GET_RAD_IMAGE_URL, diff --git a/lib/core/viewModels/AlHabibMedicalService/add_new_address_Request_Model.dart b/lib/core/viewModels/AlHabibMedicalService/add_new_address_Request_Model.dart index 5bde5a5f..23329a89 100644 --- a/lib/core/viewModels/AlHabibMedicalService/add_new_address_Request_Model.dart +++ b/lib/core/viewModels/AlHabibMedicalService/add_new_address_Request_Model.dart @@ -55,7 +55,7 @@ class Addresses { String firstName; String lastName; String email; - Null company; + dynamic company; int countryId; String country; Null stateProvinceId; @@ -64,7 +64,7 @@ class Addresses { String address2; String zipPostalCode; String phoneNumber; - Null faxNumber; + dynamic faxNumber; String customerAttributes; String createdOnUtc; Null province; diff --git a/lib/core/viewModels/AlHabibMedicalService/home_health_care_view_model.dart b/lib/core/viewModels/AlHabibMedicalService/home_health_care_view_model.dart index 5bab0df5..32644fd4 100644 --- a/lib/core/viewModels/AlHabibMedicalService/home_health_care_view_model.dart +++ b/lib/core/viewModels/AlHabibMedicalService/home_health_care_view_model.dart @@ -40,6 +40,8 @@ class HomeHealthCareViewModel extends BaseViewModel { PharmacyModuleService _pharmacyModuleService = locator(); + + bool get isOrderUpdated => _homeHealthCareService.isOrderUpdated; GetHHCAllPresOrdersResponseModel pendingOrder; @@ -136,9 +138,13 @@ class HomeHealthCareViewModel extends BaseViewModel { {AddNewAddressRequestModel addNewAddressRequestModel}) async { setState(ViewState.Busy); - await _customerAddressesService.addAddressInfo( - addNewAddressRequestModel: addNewAddressRequestModel - ); + + await _pharmacyModuleService.generatePharmacyToken().then((value) async{ + await _customerAddressesService.addAddressInfo( + addNewAddressRequestModel: addNewAddressRequestModel + ); + }); + if (_customerAddressesService.hasError) { error = _customerAddressesService.error; setState(ViewState.ErrorLocal); diff --git a/lib/core/viewModels/medical/EyeViewModel.dart b/lib/core/viewModels/medical/EyeViewModel.dart index d6c3bf80..ab76b94f 100644 --- a/lib/core/viewModels/medical/EyeViewModel.dart +++ b/lib/core/viewModels/medical/EyeViewModel.dart @@ -43,4 +43,34 @@ class EyeViewModel extends BaseViewModel { setState(ViewState.Idle); } } + + sendGlassesPrescriptionEmail({int appointmentNo, String projectName, int projectID}) async { + setState(ViewState.Busy); + await _eyeService.sendGlassesPrescriptionEmail( + appointmentNo: appointmentNo, + projectID: projectID, + projectName: projectName); + if (_eyeService.hasError) { + error = _eyeService.error; + setState(ViewState.Error); + } else { + setState(ViewState.Idle); + } + } + + sendContactLensPrescriptionEmail({int appointmentNo, String projectName, int projectID}) async { + setState(ViewState.Busy); + await _eyeService.sendContactLensPrescriptionEmail( + appointmentNo: appointmentNo, + projectID: projectID, + projectName: projectName); + if (_eyeService.hasError) { + error = _eyeService.error; + setState(ViewState.Error); + } else { + setState(ViewState.Idle); + } + } + + } diff --git a/lib/pages/AlHabibMedicalService/HomeHealthCare/NewHomeHealthCare/location_page.dart b/lib/pages/AlHabibMedicalService/HomeHealthCare/NewHomeHealthCare/location_page.dart index c9e4262f..c87a3eb5 100644 --- a/lib/pages/AlHabibMedicalService/HomeHealthCare/NewHomeHealthCare/location_page.dart +++ b/lib/pages/AlHabibMedicalService/HomeHealthCare/NewHomeHealthCare/location_page.dart @@ -122,6 +122,7 @@ class _LocationPageState } }); + await model.addAddressInfo( addNewAddressRequestModel: addNewAddressRequestModel); if (model.state == ViewState.ErrorLocal) { @@ -130,7 +131,7 @@ class _LocationPageState AppToast.showSuccessToast( message: "Address Added Successfully"); } - Navigator.of(context).pop(); + Navigator.of(context).pop(addNewAddressRequestModel); }, label: TranslationBase.of(context).addNewAddress, ), diff --git a/lib/pages/medical/balance/advance_payment_page.dart b/lib/pages/medical/balance/advance_payment_page.dart index 6611c779..5b2b5d56 100644 --- a/lib/pages/medical/balance/advance_payment_page.dart +++ b/lib/pages/medical/balance/advance_payment_page.dart @@ -237,7 +237,7 @@ class _AdvancePaymentPageState extends State { ), ), bottomSheet: Container( - height: MediaQuery.of(context).size.height * 0.10, + height: 90, width: double.infinity, padding: EdgeInsets.all(18), child: SecondaryButton( diff --git a/lib/pages/medical/balance/my_balance_page.dart b/lib/pages/medical/balance/my_balance_page.dart index 8f80eeeb..7639bb2f 100644 --- a/lib/pages/medical/balance/my_balance_page.dart +++ b/lib/pages/medical/balance/my_balance_page.dart @@ -49,7 +49,7 @@ class MyBalancePage extends StatelessWidget { width: double.infinity, height: 65, decoration: BoxDecoration( - color: Theme.of(context).primaryColor, + color: Colors.red[700], shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(7), ), @@ -79,7 +79,7 @@ class MyBalancePage extends StatelessWidget { height: 65, margin: EdgeInsets.only(top: 8), decoration: BoxDecoration( - color: Theme.of(context).primaryColor, + color: Colors.white, shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(7), ), diff --git a/lib/pages/medical/eye/ClassesPage.dart b/lib/pages/medical/eye/ClassesPage.dart index 7904178c..21a07d23 100644 --- a/lib/pages/medical/eye/ClassesPage.dart +++ b/lib/pages/medical/eye/ClassesPage.dart @@ -1,17 +1,28 @@ import 'package:diplomaticquarterapp/core/model/eye/AppoimentAllHistoryResult.dart'; import 'package:diplomaticquarterapp/core/viewModels/medical/EyeViewModel.dart'; import 'package:diplomaticquarterapp/pages/base/base_view.dart'; +import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/widgets/buttons/secondary_button.dart'; import 'package:diplomaticquarterapp/widgets/data_display/text.dart'; +import 'package:diplomaticquarterapp/widgets/dialogs/confirm_send_email_dialog.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class ClassesPage extends StatelessWidget { final ListHISGetGlassPerscription glassPerscription; + final int appointmentNo; + final String projectName; + final int projectID; - const ClassesPage({Key key, this.glassPerscription}) : super(key: key); + const ClassesPage( + {Key key, + this.glassPerscription, + this.appointmentNo, + this.projectName, + this.projectID}) + : super(key: key); @override Widget build(BuildContext context) { @@ -38,11 +49,16 @@ class ClassesPage extends StatelessWidget { bold: true, ), ), - getRow(TranslationBase.of(context).sphere, '${glassPerscription.rightEyeSpherical}', '-'), - getRow(TranslationBase.of(context).cylinder, '${glassPerscription.rightEyeCylinder}', '-'), - getRow(TranslationBase.of(context).axis, '${glassPerscription.rightEyeAxis}', '-'), - getRow(TranslationBase.of(context).prism, '${glassPerscription.rightEyePrism}', '-'), - getRow(TranslationBase.of(context).va, '${glassPerscription.rightEyeVA}', '-'), + getRow(TranslationBase.of(context).sphere, + '${glassPerscription.rightEyeSpherical}', '-'), + getRow(TranslationBase.of(context).cylinder, + '${glassPerscription.rightEyeCylinder}', '-'), + getRow(TranslationBase.of(context).axis, + '${glassPerscription.rightEyeAxis}', '-'), + getRow(TranslationBase.of(context).prism, + '${glassPerscription.rightEyePrism}', '-'), + getRow(TranslationBase.of(context).va, + '${glassPerscription.rightEyeVA}', '-'), ], ), ), @@ -65,11 +81,16 @@ class ClassesPage extends StatelessWidget { bold: true, ), ), - getRow(TranslationBase.of(context).sphere, '${glassPerscription.leftEyeSpherical}', '-'), - getRow(TranslationBase.of(context).cylinder, '${glassPerscription.leftEyeCylinder}', '-'), - getRow(TranslationBase.of(context).axis, '${glassPerscription.leftEyeAxis}', '-'), - getRow(TranslationBase.of(context).prism, '${glassPerscription.leftEyePrism}', '-'), - getRow(TranslationBase.of(context).va, '${glassPerscription.leftEyeVA}', '-'), + getRow(TranslationBase.of(context).sphere, + '${glassPerscription.leftEyeSpherical}', '-'), + getRow(TranslationBase.of(context).cylinder, + '${glassPerscription.leftEyeCylinder}', '-'), + getRow(TranslationBase.of(context).axis, + '${glassPerscription.leftEyeAxis}', '-'), + getRow(TranslationBase.of(context).prism, + '${glassPerscription.leftEyePrism}', '-'), + getRow(TranslationBase.of(context).va, + '${glassPerscription.leftEyeVA}', '-'), ], ), ), @@ -80,6 +101,16 @@ class ClassesPage extends StatelessWidget { width: double.infinity, child: SecondaryButton( label: TranslationBase.of(context).sendEmail, + onTap: () { + showConfirmMessage(context, () async { + GifLoaderDialogUtils.showMyDialog(context); + await model.sendGlassesPrescriptionEmail( + appointmentNo: appointmentNo, + projectName: projectName, + projectID: projectID); + GifLoaderDialogUtils.hideDialog(context); + }, model.user.emailAddress); + }, textColor: Colors.white, color: Colors.red[700], icon: Icon( @@ -96,6 +127,19 @@ class ClassesPage extends StatelessWidget { ); } + void showConfirmMessage( + BuildContext context, GestureTapCallback onTap, String email) { + showDialog( + context: context, + child: ConfirmSendEmailDialog( + email: email, + onTapSendEmail: () { + onTap(); + }, + ), + ); + } + Widget getRow(String title, String val1, String val2) => Padding( padding: const EdgeInsets.all(8.0), child: Column( @@ -113,7 +157,7 @@ class ClassesPage extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Texts(val1 == 'null' ? '-' : val1), - Texts(val2 != 'null' ? '-' :val2), + Texts(val2 != 'null' ? '-' : val2), ], ), ) diff --git a/lib/pages/medical/eye/ContactLensPage.dart b/lib/pages/medical/eye/ContactLensPage.dart index 373c3c79..b70b9c09 100644 --- a/lib/pages/medical/eye/ContactLensPage.dart +++ b/lib/pages/medical/eye/ContactLensPage.dart @@ -1,8 +1,12 @@ import 'package:diplomaticquarterapp/core/model/eye/AppoimentAllHistoryResult.dart'; +import 'package:diplomaticquarterapp/core/viewModels/medical/EyeViewModel.dart'; import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; +import 'package:diplomaticquarterapp/pages/base/base_view.dart'; +import 'package:diplomaticquarterapp/uitl/gif_loader_dialog_utils.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/widgets/buttons/secondary_button.dart'; import 'package:diplomaticquarterapp/widgets/data_display/text.dart'; +import 'package:diplomaticquarterapp/widgets/dialogs/confirm_send_email_dialog.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -10,95 +14,126 @@ import 'package:provider/provider.dart'; class ContactLensPage extends StatelessWidget { final ListHISGetContactLensPerscription listHISGetContactLensPerscription; + final int appointmentNo; + final String projectName; + final int projectID; - const ContactLensPage({Key key, this.listHISGetContactLensPerscription}) + const ContactLensPage( + {Key key, + this.listHISGetContactLensPerscription, + this.appointmentNo, + this.projectName, + this.projectID}) : super(key: key); @override Widget build(BuildContext context) { ProjectViewModel projectViewModel = Provider.of(context); - return AppScaffold( - body: SingleChildScrollView( - child: Container( - margin: EdgeInsets.only(top: 70, left: 15, right: 15, bottom: 15), - child: Column( - children: [ - Container( - decoration: BoxDecoration( - shape: BoxShape.rectangle, - borderRadius: BorderRadius.all(Radius.circular(8)), - color: Colors.white), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Texts( - TranslationBase.of(context).rightEye, - fontSize: 23, - bold: true, + return BaseView( + builder: (_,model,w)=> + AppScaffold( + body: SingleChildScrollView( + child: Container( + margin: EdgeInsets.only(top: 70, left: 15, right: 15, bottom: 15), + child: Column( + children: [ + Container( + decoration: BoxDecoration( + shape: BoxShape.rectangle, + borderRadius: BorderRadius.all(Radius.circular(8)), + color: Colors.white), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Texts( + TranslationBase.of(context).rightEye, + fontSize: 23, + bold: true, + ), ), - ), - getRow(TranslationBase.of(context).brand, '${listHISGetContactLensPerscription.brand}'), - getRow('B.C', '${listHISGetContactLensPerscription.baseCurve}'), - getRow(TranslationBase.of(context).power, '${listHISGetContactLensPerscription.power}'), - getRow(TranslationBase.of(context).diameter, '${listHISGetContactLensPerscription.diameter}'), - getRow('OZ', '${listHISGetContactLensPerscription.oZ}'), - getRow('CT', '${listHISGetContactLensPerscription.cT}'), - getRow('Blend', '${listHISGetContactLensPerscription.blend}'), - getRow(TranslationBase.of(context).reminder, '${listHISGetContactLensPerscription.remarks}'), - - - ], + getRow(TranslationBase.of(context).brand, + '${listHISGetContactLensPerscription.brand}'), + getRow('B.C', + '${listHISGetContactLensPerscription.baseCurve}'), + getRow(TranslationBase.of(context).power, + '${listHISGetContactLensPerscription.power}'), + getRow(TranslationBase.of(context).diameter, + '${listHISGetContactLensPerscription.diameter}'), + getRow('OZ', '${listHISGetContactLensPerscription.oZ}'), + getRow('CT', '${listHISGetContactLensPerscription.cT}'), + getRow( + 'Blend', '${listHISGetContactLensPerscription.blend}'), + getRow(TranslationBase.of(context).reminder, + '${listHISGetContactLensPerscription.remarks}'), + ], + ), ), - ), - SizedBox( - height: 17, - ), - Container( - decoration: BoxDecoration( - shape: BoxShape.rectangle, - borderRadius: BorderRadius.all(Radius.circular(8)), - color: Colors.white), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Texts( - TranslationBase.of(context).leftEye, - fontSize: 23, - bold: true, - ), - ), - getRow(TranslationBase.of(context).brand, '${listHISGetContactLensPerscription.brand}'), - getRow('B.C', '${listHISGetContactLensPerscription.baseCurve}'), - getRow(TranslationBase.of(context).power, '${listHISGetContactLensPerscription.power}'), - getRow(TranslationBase.of(context).diameter, '${listHISGetContactLensPerscription.diameter}'), - getRow('OZ', '${listHISGetContactLensPerscription.oZ}'), - getRow('CT', '${listHISGetContactLensPerscription.cT}'), - getRow('Blend', '${listHISGetContactLensPerscription.blend}'), - getRow(TranslationBase.of(context).reminder, '${listHISGetContactLensPerscription.remarks}'), - ], + SizedBox( + height: 17, ), - ), - SizedBox( - height: 17, - ), - if(projectViewModel.havePrivilege(15)) - Container( - width: double.infinity, - child: SecondaryButton( - label: TranslationBase.of(context).sendEmail, - textColor: Colors.white, - color: Colors.red[700], - icon: Icon( - Icons.email, - color: Colors.white, + Container( + decoration: BoxDecoration( + shape: BoxShape.rectangle, + borderRadius: BorderRadius.all(Radius.circular(8)), + color: Colors.white), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Texts( + TranslationBase.of(context).leftEye, + fontSize: 23, + bold: true, + ), + ), + getRow(TranslationBase.of(context).brand, + '${listHISGetContactLensPerscription.brand}'), + getRow('B.C', + '${listHISGetContactLensPerscription.baseCurve}'), + getRow(TranslationBase.of(context).power, + '${listHISGetContactLensPerscription.power}'), + getRow(TranslationBase.of(context).diameter, + '${listHISGetContactLensPerscription.diameter}'), + getRow('OZ', '${listHISGetContactLensPerscription.oZ}'), + getRow('CT', '${listHISGetContactLensPerscription.cT}'), + getRow( + 'Blend', '${listHISGetContactLensPerscription.blend}'), + getRow(TranslationBase.of(context).reminder, + '${listHISGetContactLensPerscription.remarks}'), + ], ), ), - ) - ], + SizedBox( + height: 17, + ), + if (projectViewModel.havePrivilege(15)) + Container( + width: double.infinity, + child: SecondaryButton( + label: TranslationBase.of(context).sendEmail, + textColor: Colors.white, + color: Colors.red[700], + onTap: (){ + showConfirmMessage(context, () async { + GifLoaderDialogUtils.showMyDialog(context); + await model.sendContactLensPrescriptionEmail( + appointmentNo: appointmentNo, + projectName: projectName, + projectID: projectID); + GifLoaderDialogUtils.hideDialog(context); + }, model.user.emailAddress); + }, + icon: Icon( + Icons.email, + color: Colors.white, + ), + ), + ) + ], + ), ), ), ), @@ -130,4 +165,18 @@ class ContactLensPage extends StatelessWidget { ], ), ); + + + void showConfirmMessage( + BuildContext context, GestureTapCallback onTap, String email) { + showDialog( + context: context, + child: ConfirmSendEmailDialog( + email: email, + onTapSendEmail: () { + onTap(); + }, + ), + ); + } } diff --git a/lib/pages/medical/eye/EyeHomePage.dart b/lib/pages/medical/eye/EyeHomePage.dart index bce778b8..3af2279e 100644 --- a/lib/pages/medical/eye/EyeHomePage.dart +++ b/lib/pages/medical/eye/EyeHomePage.dart @@ -43,6 +43,7 @@ class _EyeHomePageState extends State Widget build(BuildContext context) { return AppScaffold( isShowAppBar: true, + isShowDecPage: false, appBarTitle: TranslationBase.of(context).measurements, body: Scaffold( extendBodyBehindAppBar: true, @@ -81,13 +82,13 @@ class _EyeHomePageState extends State unselectedLabelColor: Colors.grey[800], tabs: [ Container( - width: MediaQuery.of(context).size.width * 0.27, + width: MediaQuery.of(context).size.width * 0.40, child: Center( child: Texts(TranslationBase.of(context).classes), ), ), Container( - width: MediaQuery.of(context).size.width * 0.27, + width: MediaQuery.of(context).size.width * 0.40, child: Center( child: Texts(TranslationBase.of(context).contactLens), ), @@ -110,11 +111,15 @@ class _EyeHomePageState extends State ClassesPage( glassPerscription: widget.appointmentAllHistoryResultList .listHISGetGlassPerscription[0], + appointmentNo: widget.appointmentAllHistoryResultList.appointmentNo, + projectName: widget.appointmentAllHistoryResultList.projectName, + projectID: widget.appointmentAllHistoryResultList.projectID, ), ContactLensPage( - listHISGetContactLensPerscription: widget - .appointmentAllHistoryResultList - .listHISGetContactLensPerscription[0], + listHISGetContactLensPerscription: widget.appointmentAllHistoryResultList.listHISGetContactLensPerscription[0], + appointmentNo: widget.appointmentAllHistoryResultList.appointmentNo, + projectName: widget.appointmentAllHistoryResultList.projectName, + projectID: widget.appointmentAllHistoryResultList.projectID, ) ], ), diff --git a/lib/pages/medical/prescriptions/PrescriptionIDeliveryAddressPage.dart b/lib/pages/medical/prescriptions/PrescriptionIDeliveryAddressPage.dart index 88234fe5..8f04d3a0 100644 --- a/lib/pages/medical/prescriptions/PrescriptionIDeliveryAddressPage.dart +++ b/lib/pages/medical/prescriptions/PrescriptionIDeliveryAddressPage.dart @@ -4,6 +4,7 @@ import 'package:diplomaticquarterapp/core/model/prescriptions/Prescriptions.dart import 'package:diplomaticquarterapp/core/model/prescriptions/prescription_report.dart'; import 'package:diplomaticquarterapp/core/model/prescriptions/prescription_report_enh.dart'; import 'package:diplomaticquarterapp/core/service/AlHabibMedicalService/customer_addresses_service.dart'; +import 'package:diplomaticquarterapp/core/viewModels/AlHabibMedicalService/add_new_address_Request_Model.dart'; import 'package:diplomaticquarterapp/core/viewModels/medical/PrescriptionDeliveryViewModel.dart'; import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; import 'package:diplomaticquarterapp/pages/AlHabibMedicalService/HomeHealthCare/NewHomeHealthCare/location_page.dart'; @@ -212,7 +213,51 @@ class _PrescriptionDeliveryAddressPageState latitude: latitude, longitude: longitude, )), - ); + ).then((value) { + if (value != null && + value is AddNewAddressRequestModel) { + setState(() { + _selectedAddress = AddressInfo( + id: value.customer.id.toString(), + email: value.customer.email, + firstName: value.customer.addresses[0].firstName, + lastName: value.customer.addresses[0].lastName, + address1: value.customer.addresses[0].address1, + address2: value.customer.addresses[0].address2, + city: value.customer.addresses[0].city, + country: value.customer.addresses[0].country, + phoneNumber: value.customer.addresses[0].phoneNumber, + latLong: value.customer.addresses[0].latLong, + company: value.customer.addresses[0].company, + countryId: value.customer.addresses[0].countryId, + createdOnUtc: value.customer.addresses[0].createdOnUtc, + customerAttributes: value.customer.addresses[0].customerAttributes, + faxNumber: value.customer.addresses[0].faxNumber, + province: value.customer.addresses[0].province, + stateProvinceId: value.customer.addresses[0].stateProvinceId, + zipPostalCode: value.customer.addresses[0].zipPostalCode, + + ); + List latLongArr = _selectedAddress.latLong.split(','); + + latitude = double.parse(latLongArr[0]); + longitude = double.parse(latLongArr[1]); + markers = Set(); + markers.add( + Marker( + markerId: MarkerId( + _selectedAddress.latLong.hashCode.toString(), + ), + position: LatLng(latitude, longitude), + ), + ); + _kGooglePlex = CameraPosition( + target: LatLng(latitude, longitude), + zoom: 14.4746, + ); + }); + } + }); }, ), ), diff --git a/lib/pages/medical/reports/report_home_page.dart b/lib/pages/medical/reports/report_home_page.dart index 42dcf40a..f9efb1a1 100644 --- a/lib/pages/medical/reports/report_home_page.dart +++ b/lib/pages/medical/reports/report_home_page.dart @@ -106,26 +106,26 @@ class _HomeReportPageState extends State unselectedLabelColor: Colors.grey[800], tabs: [ Container( - width: MediaQuery.of(context).size.width * 0.15, + width: MediaQuery.of(context).size.width * 0.20, child: Center( child: Texts(TranslationBase.of(context).requested,fontSize: 11,), ), ), Container( - width: MediaQuery.of(context).size.width * 0.15, + width: MediaQuery.of(context).size.width * 0.20, child: Center( child: Texts(TranslationBase.of(context).ready,fontSize: 11,), ), ), Container( - width: MediaQuery.of(context).size.width * 0.15, + width: MediaQuery.of(context).size.width * 0.20, child: Center( child: Texts(TranslationBase.of(context).completed,fontSize: 11,), ), ), Container( - width: MediaQuery.of(context).size.width * 0.15, + width: MediaQuery.of(context).size.width * 0.20, child: Center( child: Texts(TranslationBase.of(context).cancelled,fontSize: 11,), diff --git a/lib/pages/medical/reports/reports_page.dart b/lib/pages/medical/reports/reports_page.dart index d8cb2ca0..11d5fc82 100644 --- a/lib/pages/medical/reports/reports_page.dart +++ b/lib/pages/medical/reports/reports_page.dart @@ -48,16 +48,13 @@ class MedicalReports extends StatelessWidget { )), child: Row( children: [ - Expanded( - flex: 1, - child: Container( - margin: EdgeInsets.only(left: 5, right: 5), - child: LargeAvatar( - width: 50, - height: 50, - name: model.appointHistoryList[index].doctorNameObj, - url: model.appointHistoryList[index].doctorImageURL, - ), + Container( + margin: EdgeInsets.only(left: 5, right: 5), + child: LargeAvatar( + width: 50, + height: 50, + name: model.appointHistoryList[index].doctorNameObj, + url: model.appointHistoryList[index].doctorImageURL, ), ), Expanded( @@ -85,29 +82,26 @@ class MedicalReports extends StatelessWidget { ), ), ), - Expanded( - flex: 1, - child: InkWell( - onTap: () => - confirmBox(model.appointHistoryList[index], model), - child: Container( - width: 85, - height: 50, - decoration: BoxDecoration( - color: Colors.black54, - border: - Border.all(color: Colors.transparent, width: 2), - shape: BoxShape.rectangle, - borderRadius: BorderRadius.all( - Radius.circular(8.0), - ), + InkWell( + onTap: () => + confirmBox(model.appointHistoryList[index], model), + child: Container( + width: 120, + height: 50, + decoration: BoxDecoration( + color: Colors.black54, + border: + Border.all(color: Colors.transparent, width: 2), + shape: BoxShape.rectangle, + borderRadius: BorderRadius.all( + Radius.circular(8.0), ), - child: Center( - child: Texts( - TranslationBase.of(context).requestReport, - fontSize: 12, - color: Colors.white, - ), + ), + child: Center( + child: Texts( + TranslationBase.of(context).requestReport, + fontSize: 12, + color: Colors.white, ), ), ), diff --git a/lib/pages/medical/vital_sign/LineChartCurvedBloodPressure.dart b/lib/pages/medical/vital_sign/LineChartCurvedBloodPressure.dart index 605e264a..2d95f08c 100644 --- a/lib/pages/medical/vital_sign/LineChartCurvedBloodPressure.dart +++ b/lib/pages/medical/vital_sign/LineChartCurvedBloodPressure.dart @@ -81,7 +81,7 @@ class LineChartCurvedBloodPressure extends StatelessWidget { height: 20, decoration: BoxDecoration( shape: BoxShape.rectangle, - color: Colors.grey), + color: Colors.red), ), SizedBox(width: 5,), Texts(TranslationBase.of(context).diastolicLng) @@ -125,7 +125,6 @@ class LineChartCurvedBloodPressure extends StatelessWidget { fontSize: 10, ), rotateAngle: -65, - //rotateAngle:-65, margin: 22, getTitles: (value) { if (timeSeries1.length < 15) { diff --git a/lib/pages/paymentService/payment_service.dart b/lib/pages/paymentService/payment_service.dart index cca506ec..1b221454 100644 --- a/lib/pages/paymentService/payment_service.dart +++ b/lib/pages/paymentService/payment_service.dart @@ -117,7 +117,7 @@ class PaymentService extends StatelessWidget { ) ], ), - // if(!projectViewModel.havePrivilege(33)) + //if(!projectViewModel.havePrivilege(33)) Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ From e5474b30629a2d655318be6643aa4698a2a8f88b Mon Sep 17 00:00:00 2001 From: mosazaid Date: Thu, 18 Mar 2021 09:58:47 +0200 Subject: [PATCH 21/26] fix perscription pages bugs --- lib/config/localized_values.dart | 5 +- .../prescriptions/prescription_report.dart | 230 +++++++++++------- .../widgets/AppointmentActions.dart | 23 +- .../widgets/reminder_dialog.dart | 26 +- .../pharmacy_for_prescriptions_page.dart | 2 +- .../prescription_details_page.dart | 168 ++++++++++--- .../pharmacyAddresses/PharmacyAddresses.dart | 2 +- lib/uitl/translations_delegate_base.dart | 1 + 8 files changed, 321 insertions(+), 136 deletions(-) diff --git a/lib/config/localized_values.dart b/lib/config/localized_values.dart index 78a4fa8b..1670930c 100644 --- a/lib/config/localized_values.dart +++ b/lib/config/localized_values.dart @@ -643,8 +643,8 @@ const Map localizedValues = { "Remarks": {"en": "Remarks", "ar": "ملاحضات"}, "ActiveMedications": {"en": "Active Medications", "ar": "ادويتي النشطة"}, "ExpDate": {"en": "Active Exp Date :", "VA": "تاريخ الإنتهاء"}, - "Route": {"en": "Route :", "ar": "الطريقة"}, - "Frequency": {"en": "Frequency :", "ar": "المعدل"}, + "Route": {"en": "Route", "ar": "الطريقة"}, + "Frequency": {"en": "Frequency", "ar": "المعدل"}, "DailyQuantity": {"en": "Daily Quantity :", "ar": "جرعات يومية"}, "AddReminder": {"en": "Add Reminder", "ar": "إضافة تذكير"}, "reminderDes": { @@ -1084,6 +1084,7 @@ const Map localizedValues = { "Average": {"en": "Average", "ar": "المعدل"}, "DailyDoses": {"en": "Daily Doses", "ar": "جرعات يومية"}, "Period": {"en": "Period", "ar": "الفترة"}, + "duration": {"en": "Duration", "ar": "المدة"}, "cm": {"en": "CM", "ar": "سم"}, "ft": {"en": "ft", "ar": "قدم"}, "kg": {"en": "kg", "ar": "كجم"}, diff --git a/lib/core/model/prescriptions/prescription_report.dart b/lib/core/model/prescriptions/prescription_report.dart index 51f5750f..8c18df62 100644 --- a/lib/core/model/prescriptions/prescription_report.dart +++ b/lib/core/model/prescriptions/prescription_report.dart @@ -1,127 +1,193 @@ import 'package:diplomaticquarterapp/uitl/date_uitl.dart'; class PrescriptionReport { + String address; + int appointmentNo; + String clinic; + String companyName; + int days; + String doctorName; + var doseDailyQuantity; + String frequency; + int frequencyNumber; + String image; + String imageExtension; + String imageSRCUrl; + String imageString; + String imageThumbUrl; + String isCovered; + String itemDescription; + int itemID; + String orderDate; int patientID; String patientName; + String phoneOffice1; + String prescriptionQR; + int prescriptionTimes; + String productImage; + String productImageBase64; + String productImageString; + int projectID; + String projectName; + String remarks; + String route; + String sKU; + int scaleOffset; + String startDate; + String patientAge; String patientGender; - String address; String phoneOffice; - String itemDescription; int doseTimingID; int frequencyID; int routeID; - String clinic; - String doctorName; - String route; - String frequency; - String remarks; String name; - int days; - String startDate; - String orderDate; - int doseDailyQuantity; - int itemID; - Null productImage; - String sKU; String itemDescriptionN; String routeN; String frequencyN; - String imageSRCUrl; - String imageThumbUrl; - PrescriptionReport( - {this.patientID, - this.patientName, - this.patientAge, - this.patientGender, - this.address, - this.phoneOffice, - this.itemDescription, - this.doseTimingID, - this.frequencyID, - this.routeID, - this.clinic, - this.doctorName, - this.route, - this.frequency, - this.remarks, - this.name, - this.days, - this.startDate, - this.orderDate, - this.doseDailyQuantity, - this.itemID, - this.productImage, - this.sKU, - this.itemDescriptionN, - this.routeN, - this.frequencyN, - this.imageSRCUrl, - this.imageThumbUrl}); + PrescriptionReport({ + this.address, + this.appointmentNo, + this.clinic, + this.companyName, + this.days, + this.doctorName, + this.doseDailyQuantity, + this.frequency, + this.frequencyNumber, + this.image, + this.imageExtension, + this.imageSRCUrl, + this.imageString, + this.imageThumbUrl, + this.isCovered, + this.itemDescription, + this.itemID, + this.orderDate, + this.patientID, + this.patientName, + this.phoneOffice1, + this.prescriptionQR, + this.prescriptionTimes, + this.productImage, + this.productImageBase64, + this.productImageString, + this.projectID, + this.projectName, + this.remarks, + this.route, + this.sKU, + this.scaleOffset, + this.startDate, + this.patientAge, + this.patientGender, + this.phoneOffice, + this.doseTimingID, + this.frequencyID, + this.routeID, + this.name, + this.itemDescriptionN, + this.routeN, + this.frequencyN, + }); PrescriptionReport.fromJson(Map json) { - patientID = json['PatientID']; - patientName = json['PatientName']; - patientAge = json['PatientAge']; - patientGender = json['PatientGender']; address = json['Address']; - phoneOffice = json['PhoneOffice']; - itemDescription = json['ItemDescription']; - doseTimingID = json['DoseTimingID']; - frequencyID = json['FrequencyID']; - routeID = json['RouteID']; + appointmentNo = json['AppointmentNo']; clinic = json['Clinic']; - doctorName = json['DoctorName']; - route = json['Route']; - frequency = json['Frequency']; - remarks = json['Remarks']; - name = json['Name']; + companyName = json['CompanyName']; days = json['Days']; - startDate = json['StartDate']; - orderDate = json['OrderDate']; + doctorName = json['DoctorName']; doseDailyQuantity = json['DoseDailyQuantity']; + frequency = json['Frequency']; + frequencyNumber = json['FrequencyNumber']; + image = json['Image']; + imageExtension = json['ImageExtension']; + imageSRCUrl = json['ImageSRCUrl']; + imageString = json['ImageString']; + imageThumbUrl = json['ImageThumbUrl']; + isCovered = json['IsCovered']; + itemDescription = json['ItemDescription']; itemID = json['ItemID']; + orderDate = json['OrderDate']; + patientID = json['PatientID']; + patientName = json['PatientName']; + phoneOffice1 = json['PhoneOffice1']; + prescriptionQR = json['PrescriptionQR']; + prescriptionTimes = json['PrescriptionTimes']; productImage = json['ProductImage']; + productImageBase64 = json['ProductImageBase64']; + productImageString = json['ProductImageString']; + projectID = json['ProjectID']; + projectName = json['ProjectName']; + remarks = json['Remarks']; + route = json['Route']; sKU = json['SKU']; - itemDescriptionN = json['ItemDescriptionN']; - routeN = json['RouteN']; - frequencyN = json['FrequencyN']; - imageSRCUrl = json['ImageSRCUrl']; - imageThumbUrl = json['ImageThumbUrl']; + scaleOffset = json['ScaleOffset']; + startDate = json['StartDate']; + + patientAge = json['patientAge']; + patientGender = json['patientGender']; + phoneOffice = json['phoneOffice']; + doseTimingID = json['doseTimingID']; + frequencyID = json['frequencyID']; + routeID = json['routeID']; + name = json['name']; + itemDescriptionN = json['itemDescriptionN']; + routeN = json['routeN']; + frequencyN = json['frequencyN']; } Map toJson() { final Map data = new Map(); + + data['Address'] = this.address; + data['AppointmentNo'] = this.appointmentNo; + data['Clinic'] = this.clinic; + data['CompanyName'] = this.companyName; + data['Days'] = this.days; + data['DoctorName'] = this.doctorName; + data['DoseDailyQuantity'] = this.doseDailyQuantity; + data['Frequency'] = this.frequency; + data['FrequencyNumber'] = this.frequencyNumber; + data['Image'] = this.image; + data['ImageExtension'] = this.imageExtension; + data['ImageSRCUrl'] = this.imageSRCUrl; + data['ImageString'] = this.imageString; + data['ImageThumbUrl'] = this.imageThumbUrl; + data['IsCovered'] = this.isCovered; + data['ItemDescription'] = this.itemDescription; + data['ItemID'] = this.itemID; + data['OrderDate'] = this.orderDate; data['PatientID'] = this.patientID; data['PatientName'] = this.patientName; + data['PhoneOffice1'] = this.phoneOffice1; + data['PrescriptionQR'] = this.prescriptionQR; + data['PrescriptionTimes'] = this.prescriptionTimes; + data['ProductImage'] = this.productImage; + data['ProductImageBase64'] = this.productImageBase64; + data['ProductImageString'] = this.productImageString; + data['ProjectID'] = this.projectID; + data['ProjectName'] = this.projectName; + data['Remarks'] = this.remarks; + data['Route'] = this.route; + data['SKU'] = this.sKU; + data['ScaleOffset'] = this.scaleOffset; + data['StartDate'] = this.startDate; + data['PatientAge'] = this.patientAge; data['PatientGender'] = this.patientGender; - data['Address'] = this.address; data['PhoneOffice'] = this.phoneOffice; - data['ItemDescription'] = this.itemDescription; data['DoseTimingID'] = this.doseTimingID; data['FrequencyID'] = this.frequencyID; data['RouteID'] = this.routeID; - data['Clinic'] = this.clinic; - data['DoctorName'] = this.doctorName; - data['Route'] = this.route; - data['Frequency'] = this.frequency; - data['Remarks'] = this.remarks; data['Name'] = this.name; - data['Days'] = this.days; - data['StartDate'] = this.startDate; - data['OrderDate'] = this.orderDate; - data['DoseDailyQuantity'] = this.doseDailyQuantity; - data['ItemID'] = this.itemID; - data['ProductImage'] = this.productImage; - data['SKU'] = this.sKU; data['ItemDescriptionN'] = this.itemDescriptionN; data['RouteN'] = this.routeN; data['FrequencyN'] = this.frequencyN; - data['ImageSRCUrl'] = this.imageSRCUrl; - data['ImageThumbUrl'] = this.imageThumbUrl; data['hasPlan'] = false; + return data; } } diff --git a/lib/pages/MyAppointments/widgets/AppointmentActions.dart b/lib/pages/MyAppointments/widgets/AppointmentActions.dart index 51eefe1a..b335c740 100644 --- a/lib/pages/MyAppointments/widgets/AppointmentActions.dart +++ b/lib/pages/MyAppointments/widgets/AppointmentActions.dart @@ -509,8 +509,7 @@ class _AppointmentActionsState extends State { Navigator.push( context, FadePage( - page: - LaboratoryResultPage(patientLabOrders: patientLabOrders))) + page: LaboratoryResultPage(patientLabOrders: patientLabOrders))) .then((value) {}); } @@ -518,8 +517,7 @@ class _AppointmentActionsState extends State { Navigator.push( context, FadePage( - page: - RadiologyDetailsPage(finalRadiology: finalRadiology))) + page: RadiologyDetailsPage(finalRadiology: finalRadiology))) .then((value) {}); } @@ -542,7 +540,17 @@ class _AppointmentActionsState extends State { transform: Matrix4.translationValues(0.0, curvedValue * 200, 0.0), child: Opacity( opacity: a1.value, - child: ReminderDialog(appo: appo), + child: ReminderDialog( + eventId: appo.appointmentNo.toString(), + title: "Doctor Appointment", + description: "You have an appointment with " + + appo.doctorTitle + + " " + + appo.doctorNameObj, + startDate: appo.appointmentDate, + endDate: appo.appointmentDate, + location: appo.projectName, + ), ), ); }, @@ -668,7 +676,10 @@ class _AppointmentActionsState extends State { context, FadePage( page: VitalSignDetailsScreen( - appointmentNo: appoNo, projectID: projectID,isNotOneAppointment: false,))); + appointmentNo: appoNo, + projectID: projectID, + isNotOneAppointment: false, + ))); } navigateToInsertComplaint() { diff --git a/lib/pages/MyAppointments/widgets/reminder_dialog.dart b/lib/pages/MyAppointments/widgets/reminder_dialog.dart index b8803469..0db8cda4 100644 --- a/lib/pages/MyAppointments/widgets/reminder_dialog.dart +++ b/lib/pages/MyAppointments/widgets/reminder_dialog.dart @@ -9,9 +9,14 @@ import 'package:manage_calendar_events/manage_calendar_events.dart'; class ReminderDialog extends StatefulWidget { static var selectedDuration; - AppoitmentAllHistoryResultList appo; + final String eventId; + final String title; + final String description; + final String startDate; + final String endDate; + final String location; - ReminderDialog({@required this.appo}); + ReminderDialog({@required this.eventId, @required this.title, @required this.description, @required this.startDate, @required this.endDate, @required this.location}); @override _ReminderDialogState createState() => _ReminderDialogState(); @@ -98,17 +103,14 @@ class _ReminderDialogState extends State { }); CalendarEvent calendarEvent = new CalendarEvent( - eventId: widget.appo.appointmentNo.toString(), - title: "Doctor Appointment", - description: "You have an appointment with " + - widget.appo.doctorTitle + - " " + - widget.appo.doctorNameObj, - startDate: DateUtil.convertStringToDate(widget.appo.appointmentDate) + eventId: widget.eventId, + title: widget.title, + description: widget.description, + startDate: DateUtil.convertStringToDate(widget.startDate) .subtract( new Duration(microseconds: ReminderDialog.selectedDuration)), - endDate: DateUtil.convertStringToDate(widget.appo.appointmentDate), - location: widget.appo.projectName, + endDate: DateUtil.convertStringToDate(widget.endDate), + location: widget.location, duration: new Duration(minutes: 15).inMinutes, isAllDay: false, hasAlarm: true); @@ -118,7 +120,7 @@ class _ReminderDialogState extends State { .then((value) { print("Cal event"); print(value); - if (int.parse(value) == widget.appo.appointmentNo) { + if (int.parse(value) == int.parse(widget.eventId)) { AppToast.showSuccessToast(message: TranslationBase.of(context).reminderSuccess); } Navigator.of(context).pop(); diff --git a/lib/pages/medical/prescriptions/pharmacy_for_prescriptions_page.dart b/lib/pages/medical/prescriptions/pharmacy_for_prescriptions_page.dart index 1b1eaf3f..96227fba 100644 --- a/lib/pages/medical/prescriptions/pharmacy_for_prescriptions_page.dart +++ b/lib/pages/medical/prescriptions/pharmacy_for_prescriptions_page.dart @@ -20,7 +20,7 @@ class PharmacyForPrescriptionsPage extends StatelessWidget { onModelReady: (model) => model.getListPharmacyForPrescriptions(itemId: prescriptionReport.itemID), builder: (_, model, widget) => AppScaffold( isShowAppBar: true, - appBarTitle: TranslationBase.of(context).ports, + appBarTitle: TranslationBase.of(context).availability, baseViewModel: model, body: ListView.builder( itemBuilder: (context, index) => Container( diff --git a/lib/pages/medical/prescriptions/prescription_details_page.dart b/lib/pages/medical/prescriptions/prescription_details_page.dart index d59bc06d..f40999c2 100644 --- a/lib/pages/medical/prescriptions/prescription_details_page.dart +++ b/lib/pages/medical/prescriptions/prescription_details_page.dart @@ -1,4 +1,6 @@ import 'package:diplomaticquarterapp/core/model/prescriptions/prescription_report.dart'; +import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; +import 'package:diplomaticquarterapp/pages/MyAppointments/widgets/reminder_dialog.dart'; import 'package:diplomaticquarterapp/pages/medical/prescriptions/pharmacy_for_prescriptions_page.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/widgets/data_display/text.dart'; @@ -6,6 +8,7 @@ import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; class PrescriptionDetailsPage extends StatelessWidget { final PrescriptionReport prescriptionReport; @@ -59,40 +62,49 @@ class PrescriptionDetailsPage extends StatelessWidget { ), Container( margin: EdgeInsets.all(8), - child: InkWell( - onTap: () => Navigator.push( - context, - FadePage( - page: PharmacyForPrescriptionsPage( - prescriptionReport: prescriptionReport), - ), - ), - child: Center( - child: Column( - children: [ - Container( - width: 50, - decoration: BoxDecoration( - color: Colors.white, shape: BoxShape.rectangle), + child: Row( + children: [ + Expanded( + child: InkWell( + onTap: () => Navigator.push( + context, + FadePage( + page: PharmacyForPrescriptionsPage( + prescriptionReport: prescriptionReport), + ), + ), + child: Center( child: Column( children: [ - Icon( - Icons.pin_drop, - color: Colors.red[800], - size: 55, + Container( + width: 50, + decoration: BoxDecoration( + color: Colors.white, + shape: BoxShape.rectangle), + child: Column( + children: [ + Icon( + Icons.pin_drop, + color: Colors.red[800], + size: 55, + ), + ], + ), + ), + SizedBox( + height: 5, ), + Texts(TranslationBase.of(context).availability) ], ), - ), - SizedBox( - height: 5, - ), - Texts(TranslationBase.of(context).ports) - ], - ), - )), + )), + ), + _addReminderButton(context) + ], + ), ), Container( + color: Colors.white, margin: EdgeInsets.only(top: 10, left: 10, right: 10), child: Table( border: TableBorder.symmetric( @@ -106,28 +118,28 @@ class PrescriptionDetailsPage extends StatelessWidget { height: 30, width: double.infinity, child: Center( - child: Texts(TranslationBase.of(context).way))), + child: Texts(TranslationBase.of(context).route, fontSize: 14,))), Container( color: Colors.white, height: 30, width: double.infinity, child: Center( child: - Texts(TranslationBase.of(context).average))), + Texts(TranslationBase.of(context).frequency, fontSize: 14,))), Container( color: Colors.white, - height: 30, width: double.infinity, + padding: EdgeInsets.symmetric(horizontal: 4), child: Center( child: Texts( - TranslationBase.of(context).dailyDoses))), + "${TranslationBase.of(context).dailyDoses}", fontSize: 14,))), Container( color: Colors.white, height: 30, width: double.infinity, child: Center( child: - Texts(TranslationBase.of(context).period))), + Texts(TranslationBase.of(context).duration, fontSize: 14,))), ], ), TableRow( @@ -192,4 +204,96 @@ class PrescriptionDetailsPage extends StatelessWidget { ), ); } + + Widget _addReminderButton(BuildContext context) { + ProjectViewModel projectViewModel = Provider.of(context); + + return GestureDetector( + onTap: () { + DateTime startDate = DateTime.now(); + DateTime endDate = DateTime(startDate.year, startDate.month, + startDate.day + prescriptionReport.days); + + print(prescriptionReport); + showGeneralDialog( + barrierColor: Colors.black.withOpacity(0.5), + transitionBuilder: (context, a1, a2, widget) { + final curvedValue = + Curves.easeInOutBack.transform(a1.value) - 1.0; + return Transform( + transform: + Matrix4.translationValues(0.0, curvedValue * 200, 0.0), + child: Opacity( + opacity: a1.value, + child: ReminderDialog( + eventId: prescriptionReport.itemID.toString(), + title: "Prescription Reminder", + description: + "${prescriptionReport.itemDescriptionN} ${prescriptionReport.frequencyN} ${prescriptionReport.routeN} ", + startDate: + "/Date(${startDate.millisecondsSinceEpoch}+0300)/", + endDate: "/Date(${endDate.millisecondsSinceEpoch}+0300)/", + location: prescriptionReport.remarks, + ), + ), + ); + }, + transitionDuration: Duration(milliseconds: 500), + barrierDismissible: true, + barrierLabel: '', + context: context, + pageBuilder: (context, animation1, animation2) {}); + }, + child: Column( + mainAxisSize: MainAxisSize.max, + children: [ + Container( + // height: 100.0, + margin: EdgeInsets.all(7.0), + padding: EdgeInsets.only(bottom: 4.0), + decoration: BoxDecoration(boxShadow: [ + BoxShadow( + color: Colors.grey[400], blurRadius: 2.0, spreadRadius: 0.0) + ], borderRadius: BorderRadius.circular(10), color: Colors.white), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Container( + margin: EdgeInsets.fromLTRB(5.0, 5.0, 5.0, 0.0), + child: Text("add", + overflow: TextOverflow.clip, + style: TextStyle( + color: new Color(0xffB8382C), + letterSpacing: 1.0, + fontSize: 18.0)), + ), + Container( + margin: EdgeInsets.fromLTRB(5.0, 0.0, 5.0, 0.0), + child: Text("reminder", + overflow: TextOverflow.clip, + style: TextStyle( + color: Colors.black, + letterSpacing: 1.0, + fontSize: 15.0)), + ), + Container( + alignment: projectViewModel.isArabic + ? Alignment.bottomLeft + : Alignment.bottomRight, + margin: projectViewModel.isArabic + ? EdgeInsets.fromLTRB(10.0, 7.0, 0.0, 8.0) + : EdgeInsets.fromLTRB(0.0, 7.0, 10.0, 8.0), + child: Image.asset( + "assets/images/new-design/reminder_icon.png", + width: 45.0, + height: 45.0), + ), + ], + ), + ), + ], + ), + ); + } } diff --git a/lib/pages/pharmacy/pharmacyAddresses/PharmacyAddresses.dart b/lib/pages/pharmacy/pharmacyAddresses/PharmacyAddresses.dart index 340e2bd8..51256e11 100644 --- a/lib/pages/pharmacy/pharmacyAddresses/PharmacyAddresses.dart +++ b/lib/pages/pharmacy/pharmacyAddresses/PharmacyAddresses.dart @@ -104,7 +104,7 @@ class _PharmacyAddressesState extends State { fontWeight: FontWeight.bold, backgroundColor: Color(0xFF5AB145), fontSize: 14, - vPadding: 12, + vPadding: 8, handler: () { model.saveSelectedAddressLocally( model.addresses[model.selectedAddressIndex]); diff --git a/lib/uitl/translations_delegate_base.dart b/lib/uitl/translations_delegate_base.dart index a90f8614..74922edc 100644 --- a/lib/uitl/translations_delegate_base.dart +++ b/lib/uitl/translations_delegate_base.dart @@ -985,6 +985,7 @@ class TranslationBase { String get average => localizedValues['Average'][locale.languageCode]; String get dailyDoses => localizedValues['DailyDoses'][locale.languageCode]; String get period => localizedValues['Period'][locale.languageCode]; + String get duration => localizedValues['duration'][locale.languageCode]; String get cm => localizedValues['cm'][locale.languageCode]; String get kg => localizedValues['kg'][locale.languageCode]; String get lb => localizedValues['lb'][locale.languageCode]; From 2e035e2c6b28b7fde4b21abc8de454f0578e5ad2 Mon Sep 17 00:00:00 2001 From: Elham Rababah Date: Sun, 21 Mar 2021 13:44:52 +0200 Subject: [PATCH 22/26] PAP-576: fix design --- .../AmbulanceRequestIndex.dart | 2 +- .../SelectTransportationMethod.dart | 120 +++++++++--------- 2 files changed, 64 insertions(+), 58 deletions(-) diff --git a/lib/pages/ErService/AmbulanceRequestIndexPages/AmbulanceRequestIndex.dart b/lib/pages/ErService/AmbulanceRequestIndexPages/AmbulanceRequestIndex.dart index 1fb47cec..f36eadc5 100644 --- a/lib/pages/ErService/AmbulanceRequestIndexPages/AmbulanceRequestIndex.dart +++ b/lib/pages/ErService/AmbulanceRequestIndexPages/AmbulanceRequestIndex.dart @@ -124,7 +124,7 @@ class _AmbulanceRequestIndexPageState extends State { : Column( children: [ SizedBox( - height: 80, + height: 20, ), Container( margin: EdgeInsets.only(left: 12, right: 12), diff --git a/lib/pages/ErService/AmbulanceRequestIndexPages/SelectTransportationMethod.dart b/lib/pages/ErService/AmbulanceRequestIndexPages/SelectTransportationMethod.dart index 0770448e..63d915d1 100644 --- a/lib/pages/ErService/AmbulanceRequestIndexPages/SelectTransportationMethod.dart +++ b/lib/pages/ErService/AmbulanceRequestIndexPages/SelectTransportationMethod.dart @@ -210,71 +210,77 @@ class _SelectTransportationMethodState SizedBox( height: 5, ), - Row( - children: [ - Expanded( - child: InkWell( - onTap: () { - setState(() { - _way = Way.OneWay; - }); - }, - child: Container( - decoration: BoxDecoration( - shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(8), - border: - Border.all(color: Colors.grey, width: 0.5), - color: Colors.white, - ), - child: ListTile( - title: - Texts(TranslationBase.of(context).oneDirec), - leading: Radio( - value: Way.OneWay, - groupValue: _way, - onChanged: (value) { - setState(() { - _way = value; - }); - }, + Container( + margin: EdgeInsets.only(bottom:65 ), + child: Row( + children: [ + Expanded( + child: InkWell( + onTap: () { + setState(() { + _way = Way.OneWay; + }); + }, + child: Container( + decoration: BoxDecoration( + shape: BoxShape.rectangle, + borderRadius: BorderRadius.circular(8), + border: + Border.all(color: Colors.grey, width: 0.5), + color: Colors.white, + ), + child: ListTile( + title: + Texts(TranslationBase.of(context).oneDirec), + leading: Radio( + value: Way.OneWay, + groupValue: _way, + onChanged: (value) { + setState(() { + _way = value; + }); + }, + ), ), ), ), ), - ), - Expanded( - child: InkWell( - onTap: () { - setState(() { - _way = Way.TwoWays; - }); - }, - child: Container( - decoration: BoxDecoration( - shape: BoxShape.rectangle, - borderRadius: BorderRadius.circular(8), - border: - Border.all(color: Colors.grey, width: 0.5), - color: Colors.white, - ), - child: ListTile( - title: - Texts(TranslationBase.of(context).twoDirec), - leading: Radio( - value: Way.TwoWays, - groupValue: _way, - onChanged: (value) { - setState(() { - _way = value; - }); - }, + Expanded( + child: InkWell( + onTap: () { + setState(() { + _way = Way.TwoWays; + }); + }, + child: Container( + decoration: BoxDecoration( + shape: BoxShape.rectangle, + borderRadius: BorderRadius.circular(8), + border: + Border.all(color: Colors.grey, width: 0.5), + color: Colors.white, + ), + child: ListTile( + title: + Texts(TranslationBase.of(context).twoDirec), + leading: Radio( + value: Way.TwoWays, + groupValue: _way, + onChanged: (value) { + setState(() { + _way = value; + }); + }, + ), ), ), ), ), - ), - ], + ], + ), + ), + SizedBox( + height: 30, ), ], ), From 1b770420be9983bafa35859e3bf2b5c5011d35de Mon Sep 17 00:00:00 2001 From: Sultan Khan Date: Sun, 21 Mar 2021 15:44:17 +0300 Subject: [PATCH 23/26] bug fixes --- lib/core/service/weather_service.dart | 3 +- .../ancillaryOrdersDetails.dart | 38 ++++++++++++++++++- lib/pages/DrawerPages/family/my-family.dart | 7 ++-- lib/pages/login/welcome.dart | 16 ++++---- .../authentication/auth_provider.dart | 26 ++++++------- lib/widgets/drawer/app_drawer_widget.dart | 1 + 6 files changed, 63 insertions(+), 28 deletions(-) diff --git a/lib/core/service/weather_service.dart b/lib/core/service/weather_service.dart index 10ab1adf..ea7d65bf 100644 --- a/lib/core/service/weather_service.dart +++ b/lib/core/service/weather_service.dart @@ -18,10 +18,9 @@ class WeatherService extends BaseService { var long = await sharedPref.getDouble(USER_LONG); body['Latitude'] = lat ?? 0; body['Longitude'] = long ?? 0; - + weatherIndicatorData = []; await baseAppClient.post(WEATHER_INDICATOR, onSuccess: (dynamic response, int statusCode) { - weatherIndicatorData = []; response['GetCityInfo_List'].forEach((data) { weatherIndicatorData.add(GetCityInfoList.fromJson(data)); }); diff --git a/lib/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrdersDetails.dart b/lib/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrdersDetails.dart index dc0d73d4..20d2966b 100644 --- a/lib/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrdersDetails.dart +++ b/lib/pages/AlHabibMedicalService/ancillary-orders/ancillaryOrdersDetails.dart @@ -1,6 +1,7 @@ import 'package:diplomaticquarterapp/core/viewModels/ancillary_orders_view_model.dart'; import 'package:diplomaticquarterapp/pages/base/base_view.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; +import 'package:diplomaticquarterapp/widgets/buttons/button.dart'; import 'package:diplomaticquarterapp/widgets/data_display/text.dart'; import 'package:flutter/material.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; @@ -42,7 +43,31 @@ class _AnicllaryOrdersState extends State getPatientInfo(model), getInvoiceDetails(model), getInsuranceDetails(model), - getAncillaryDetails(model) + getAncillaryDetails(model), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Texts( + TranslationBase.of(context).total, + fontSize: 20, + fontWeight: FontWeight.bold, + ), + Texts( + getTotalValue(model), + fontSize: 20, + fontWeight: FontWeight.bold, + ) + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Button( + label: TranslationBase.of(context).payNow, + onTap: () {}, + ) + ], + ) ]) : SizedBox()))); } @@ -208,7 +233,9 @@ class _AnicllaryOrdersState extends State ); list.add(Row( mainAxisAlignment: MainAxisAlignment.start, - children: [getLabDetails(value)], + children: [ + getLabDetails(value), + ], )); }); @@ -218,6 +245,13 @@ class _AnicllaryOrdersState extends State ); } + String getTotalValue(value) { + double total = 0.0; + value.ancillaryListsDetails[0].ancillaryOrderProcList + .forEach((result) => {total += result.companyShareWithTax}); + return total.toStringAsFixed(2); + } + getLabDetails(value) { return Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/pages/DrawerPages/family/my-family.dart b/lib/pages/DrawerPages/family/my-family.dart index 0a5c5091..07f99b16 100644 --- a/lib/pages/DrawerPages/family/my-family.dart +++ b/lib/pages/DrawerPages/family/my-family.dart @@ -660,14 +660,15 @@ class _MyFamily extends State with TickerProviderStateMixin { okText: TranslationBase.of(context).confirm, cancelText: TranslationBase.of(context).cancel_nocaps, okFunction: () => { - removeFamily(family, context), - ConfirmDialog.closeAlertDialog(context) + ConfirmDialog.closeAlertDialog(context), + removeFamily(family, context) }, cancelFunction: () => {}); dialog.showAlertDialog(context); } removeFamily(GetAllSharedRecordsByStatusList family, context) { + GifLoaderDialogUtils.showMyDialog(context); this.userID = family.iD; Map request = {}; request['ID'] = this.userID; @@ -679,7 +680,7 @@ class _MyFamily extends State with TickerProviderStateMixin { } refreshFamily(context) { - //sharedPref.remove(FAMILY_FILE); + GifLoaderDialogUtils.hideDialog(context); setState(() { sharedPref.remove(FAMILY_FILE); }); diff --git a/lib/pages/login/welcome.dart b/lib/pages/login/welcome.dart index b2250f5c..6a007e0a 100644 --- a/lib/pages/login/welcome.dart +++ b/lib/pages/login/welcome.dart @@ -5,6 +5,7 @@ import 'package:diplomaticquarterapp/routes.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/widgets/buttons/defaultButton.dart'; import 'package:diplomaticquarterapp/widgets/others/app_scaffold_widget.dart'; +import 'package:diplomaticquarterapp/widgets/text/app_texts_widget.dart'; import 'package:diplomaticquarterapp/widgets/transitions/fade_page.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -41,20 +42,19 @@ class _WelcomeLogin extends State { children: [ Image.asset('assets/images/DQ/logo.png', height: 90, width: 90), - Text( + AppText( TranslationBase.of(context).welcome, - style: TextStyle( - fontSize: 30, fontWeight: FontWeight.bold), - textAlign: TextAlign.start, + fontSize: 30, + fontWeight: FontWeight.bold, ), - Text( + AppText( TranslationBase.of(context).welcomeText, - style: TextStyle(fontSize: 24), + fontSize: 24, textAlign: TextAlign.start, ), - Text( + AppText( TranslationBase.of(context).welcomeText2, - style: TextStyle(fontSize: 24), + fontSize: 24, textAlign: TextAlign.start, ), SizedBox( diff --git a/lib/services/authentication/auth_provider.dart b/lib/services/authentication/auth_provider.dart index 8f0ea470..bd2006f8 100644 --- a/lib/services/authentication/auth_provider.dart +++ b/lib/services/authentication/auth_provider.dart @@ -378,24 +378,24 @@ class AuthProvider with ChangeNotifier { Future sendPatientIDSMS(mobileNo, context) async { Map request; - var languageID = - await sharedPref.getStringWithDefaultValue(APP_LANGUAGE, 'ar'); + // var languageID = + // await sharedPref.getStringWithDefaultValue(APP_LANGUAGE, 'ar'); Request req = appGlobal.getPublicRequest(); request = { - "LanguageID": languageID == 'ar' ? 1 : 2, - "IPAdress": "10.20.10.20", - "VersionID": req.VersionID, - "Channel": req.Channel, - "generalid": 'Cs2020@2016\$2958', - "PatientOutSA": 0, - "PatientID": 0, - "TokenID": "", + // "LanguageID": languageID == 'ar' ? 1 : 2, + // "IPAdress": "10.20.10.20", + // "VersionID": req.VersionID, + // "Channel": req.Channel, + // "generalid": 'Cs2020@2016\$2958', + // "PatientOutSA": 0, + // "PatientID": 0, + // "TokenID": "", "PatientMobileNumber": mobileNo, "SearchType": 2, - "ZipCode": "966", - "PatientIdentificationID": "", + // "ZipCode": "966", + // "PatientIdentificationID": "", "DeviceTypeID": req.DeviceTypeID, - "SessionID": null + // "SessionID": null }; dynamic localRes; diff --git a/lib/widgets/drawer/app_drawer_widget.dart b/lib/widgets/drawer/app_drawer_widget.dart index d5ddf3a9..c4a7d8d0 100644 --- a/lib/widgets/drawer/app_drawer_widget.dart +++ b/lib/widgets/drawer/app_drawer_widget.dart @@ -195,6 +195,7 @@ class _AppDrawerState extends State { sideArrow: true, ), onTap: () { + Navigator.of(context).pop(); Navigator.of(context).pushNamed( MY_FAMILIY, ); From efb6ea68b8a6377a059e208669f825e631aaa25f Mon Sep 17 00:00:00 2001 From: Elham Rababah Date: Sun, 21 Mar 2021 19:19:00 +0200 Subject: [PATCH 24/26] PAP-561: fix design --- lib/pages/ErService/AmbulanceRequestIndexPages/Summary.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pages/ErService/AmbulanceRequestIndexPages/Summary.dart b/lib/pages/ErService/AmbulanceRequestIndexPages/Summary.dart index 6140dc62..f8bb9e8e 100644 --- a/lib/pages/ErService/AmbulanceRequestIndexPages/Summary.dart +++ b/lib/pages/ErService/AmbulanceRequestIndexPages/Summary.dart @@ -73,6 +73,7 @@ class _SummaryState extends State { Texts(TranslationBase.of(context).billAmount,textAlign: TextAlign.start,), SizedBox(height: 5,), Container( + height: 55, padding: EdgeInsets.all(10), decoration: BoxDecoration( @@ -87,8 +88,8 @@ class _SummaryState extends State { ], ), ), + SizedBox(height: 250), - SizedBox(height: 45,), ], ), From 8e255f1f2226131bf376e27162fcabab2718d52b Mon Sep 17 00:00:00 2001 From: Sultan Khan Date: Mon, 22 Mar 2021 08:51:54 +0300 Subject: [PATCH 25/26] bug fix --- lib/widgets/others/app_scaffold_widget.dart | 101 ++++++++++---------- 1 file changed, 48 insertions(+), 53 deletions(-) diff --git a/lib/widgets/others/app_scaffold_widget.dart b/lib/widgets/others/app_scaffold_widget.dart index 4b24af8a..ca72e267 100644 --- a/lib/widgets/others/app_scaffold_widget.dart +++ b/lib/widgets/others/app_scaffold_widget.dart @@ -87,7 +87,7 @@ class AppScaffold extends StatelessWidget { this.showHomeAppBarIcon = true, this.imagesInfo}); - AppScaffold setOnAppBarCartClick(VoidCallback onClick){ + AppScaffold setOnAppBarCartClick(VoidCallback onClick) { _onCartClick = onClick; return this; } @@ -112,21 +112,23 @@ class AppScaffold extends StatelessWidget { : null, bottomSheet: bottomSheet, body: SafeArea( - top: true, bottom: true, - child: (!Provider.of(context, listen: false).isLogin && - isShowDecPage) - ? NotAutPage( - title: title ?? appBarTitle, - description: description, - infoList: infoList, - imagesInfo: imagesInfo, - ) - : baseViewModel != null - ? NetworkBaseView( - child: buildBodyWidget(context), - baseViewModel: baseViewModel, - ) - : buildBodyWidget(context), + top: true, + bottom: true, + child: + (!Provider.of(context, listen: false).isLogin && + isShowDecPage) + ? NotAutPage( + title: title ?? appBarTitle, + description: description, + infoList: infoList, + imagesInfo: imagesInfo, + ) + : baseViewModel != null + ? NetworkBaseView( + child: buildBodyWidget(context), + baseViewModel: baseViewModel, + ) + : buildBodyWidget(context), ), ); } @@ -173,8 +175,7 @@ class AppBarWidget extends StatefulWidget with PreferredSizeWidget { Size get preferredSize => Size(double.maxFinite, 60); } -class AppBarWidgetState extends State{ - +class AppBarWidgetState extends State { String badgeText = "0"; @override Widget build(BuildContext context) { @@ -182,7 +183,7 @@ class AppBarWidgetState extends State{ return buildAppBar(context); } - badgeUpdateBlock(String value){ + badgeUpdateBlock(String value) { setState(() { badgeText = value; }); @@ -192,8 +193,9 @@ class AppBarWidgetState extends State{ ProjectViewModel projectViewModel = Provider.of(context); return AppBar( elevation: 0, - backgroundColor: - widget.isPharmacy ? Colors.green : Theme.of(context).appBarTheme.color, + backgroundColor: widget.isPharmacy + ? Colors.green + : Theme.of(context).appBarTheme.color, textTheme: TextTheme( headline6: TextStyle( color: Theme.of(context).textTheme.headline1.color, @@ -216,38 +218,32 @@ class AppBarWidgetState extends State{ actions: [ (widget.isPharmacy && widget.showPharmacyCart) ? IconButton( - icon: Badge( - badgeContent: Text( - badgeText - ), - child: Icon(Icons.shopping_cart) - ), - color: Colors.white, - onPressed: () { - Navigator.of(context).popUntil(ModalRoute.withName('/')); - }) + icon: Badge( + badgeContent: Text(badgeText), + child: Icon(Icons.shopping_cart)), + color: Colors.white, + onPressed: () { + Navigator.of(context).popUntil(ModalRoute.withName('/')); + }) : Container(), - (widget.isOfferPackages && widget.showOfferPackagesCart) ? IconButton( - 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 - if(_onCartClick != null) - _onCartClick(); - - }) + 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 + if (_onCartClick != null) _onCartClick(); + }) : Container(), - if (widget.showHomeAppBarIcon) IconButton( icon: Icon(FontAwesomeIcons.home), @@ -256,11 +252,10 @@ class AppBarWidgetState extends State{ Navigator.pushAndRemoveUntil( context, MaterialPageRoute(builder: (context) => LandingPage()), - (Route r) => false); + (Route r) => false); // Cart Click Event - if(_onCartClick != null) - _onCartClick(); + if (_onCartClick != null) _onCartClick(); }, ), if (widget.appBarIcons != null) ...widget.appBarIcons @@ -356,7 +351,7 @@ class _RobotIcon extends State { ], ), right: -30, - bottom: 50); + bottom: -15); } // setAnimation() async { From 71a393df68831824ea48e466f69631834cfe2c53 Mon Sep 17 00:00:00 2001 From: Fatimah Alshammari Date: Tue, 23 Mar 2021 12:02:46 +0300 Subject: [PATCH 26/26] fixed categories issue --- lib/config/config.dart | 2 + .../service/pharmacy_categorise_service.dart | 46 +++++ .../pharmacy_categorise_view_model.dart | 22 +++ lib/pages/final_products_page.dart | 4 + lib/pages/pharmacy_categorise.dart | 178 ++++++++++-------- 5 files changed, 177 insertions(+), 75 deletions(-) diff --git a/lib/config/config.dart b/lib/config/config.dart index 42cd755a..1ea16a37 100644 --- a/lib/config/config.dart +++ b/lib/config/config.dart @@ -509,6 +509,8 @@ const LAKUM_GET_USER_TERMS_AND_CONDITIONS = "Services/ERP.svc/REST/GetUserTermsAndConditionsForEPharmcy"; const PRESCRIPTION = 'Services/Patients.svc/REST/GetPrescriptionApptList'; const GET_RECOMMENDED_PRODUCT = 'alsoProduct/'; +const GET_MOST_VIEWED_PRODUCTS ="mostview?"; +const GET_NEW_PRODUCTS = "newproducts?"; // Home Health Care const HHC_GET_ALL_SERVICES = diff --git a/lib/core/service/pharmacy_categorise_service.dart b/lib/core/service/pharmacy_categorise_service.dart index 5ef3c1d1..58f58ddb 100644 --- a/lib/core/service/pharmacy_categorise_service.dart +++ b/lib/core/service/pharmacy_categorise_service.dart @@ -316,4 +316,50 @@ class PharmacyCategoriseService extends BaseService { }, ); } + + Future getMostViewedProducts() async { + Map queryParams = { + 'fields': + 'id,discount_ids,name,reviews,namen,localized_names,display_order,short_description,full_description,full_descriptionn,sku,order_minimum_quantity,order_maximum_quantity,price,old_price,images,is_rx,rx_message,rx_messagen,discount_name,discount_namen,approved_rating_sum,approved_total_reviews,allow_back_in_stock_subscriptions,stock_quantity,stock_availability,stock_availabilityn,discount_percentage', + }; + try { + await baseAppClient.getPharmacy(GET_MOST_VIEWED_PRODUCTS, + onSuccess: (dynamic response, int statusCode) { + _finalProducts.clear(); + response['products'].forEach((item) { + _finalProducts.add(PharmacyProduct.fromJson(item)); + }); + print("most viewed products ---------"); + print(response); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, queryParams: queryParams); + } catch (error) { + throw error; + } + } + + Future getNewProducts() async { + Map queryParams = { + 'fields': + 'Id,name,namen,localized_names,price,images,sku,stock_availability,published', + }; + try { + await baseAppClient.getPharmacy(GET_NEW_PRODUCTS, + onSuccess: (dynamic response, int statusCode) { + _finalProducts.clear(); + response['products'].forEach((item) { + _finalProducts.add(PharmacyProduct.fromJson(item)); + }); + print("new products ---------"); + print(response); + }, onFailure: (String error, int statusCode) { + hasError = true; + super.error = error; + }, queryParams: queryParams); + } catch (error) { + throw error; + } + } } diff --git a/lib/core/viewModels/pharmacy_categorise_view_model.dart b/lib/core/viewModels/pharmacy_categorise_view_model.dart index 47f64688..e48329ba 100644 --- a/lib/core/viewModels/pharmacy_categorise_view_model.dart +++ b/lib/core/viewModels/pharmacy_categorise_view_model.dart @@ -203,4 +203,26 @@ class PharmacyCategoriseViewModel extends BaseViewModel { setState(ViewState.Idle); } } + + Future getMostViewedProducts() async { + setState(ViewState.Busy); + await _pharmacyCategoriseService.getMostViewedProducts(); + if (_pharmacyCategoriseService.hasError) { + error = _pharmacyCategoriseService.error; + setState(ViewState.Error); + } else { + setState(ViewState.Idle); + } + } + + Future getNewProducts() async { + setState(ViewState.Busy); + await _pharmacyCategoriseService.getNewProducts(); + if (_pharmacyCategoriseService.hasError) { + error = _pharmacyCategoriseService.error; + setState(ViewState.Error); + } else { + setState(ViewState.Idle); + } + } } diff --git a/lib/pages/final_products_page.dart b/lib/pages/final_products_page.dart index 4820689a..66969331 100644 --- a/lib/pages/final_products_page.dart +++ b/lib/pages/final_products_page.dart @@ -41,6 +41,10 @@ class _FinalProductsPageState extends State { model.getManufacturerProducts(id); } else if (widget.productType == 3) { model.getLastVisitedProducts(); + } else if (widget.productType == 4){ + model.getMostViewedProducts(); + } else if (widget.productType == 5){ + model.getNewProducts(); } else { model.getBestSellerProducts(); } diff --git a/lib/pages/pharmacy_categorise.dart b/lib/pages/pharmacy_categorise.dart index 65886dc5..fdc1bc07 100644 --- a/lib/pages/pharmacy_categorise.dart +++ b/lib/pages/pharmacy_categorise.dart @@ -37,54 +37,56 @@ class _PharmacyCategorisePageState extends State { baseViewModel: model, body: Column( children: [ - Container( - height: 400, - margin: EdgeInsets.only(bottom: 22), - child: GridView.builder( - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - crossAxisSpacing: 0.5, - mainAxisSpacing: 1.0, - childAspectRatio: 3.2, - ), - itemCount: model.categorise.length, - itemBuilder: (BuildContext context, int index) { - return Padding( - padding: EdgeInsets.all(4.0), - child: InkWell( - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(5), - color: Colors.grey.withOpacity(0.24), - ), - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 10.0), - child: Texts( - projectViewModel.isArabic - ? model.categorise[index].namen - : model.categorise[index].name, - fontWeight: FontWeight.w600, + Expanded( + child: Container( + height: 400, + margin: EdgeInsets.only(bottom: 22), + child: GridView.builder( + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 0.5, + mainAxisSpacing: 1.0, + childAspectRatio: 3.2, + ), + itemCount: model.categorise.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.all(4.0), + child: InkWell( + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(5), + color: Colors.grey.withOpacity(0.24), ), - ), - ), - onTap: () => { - Navigator.push( - context, - FadePage( - page: model.categorise[index].id != '12' - ? ParentCategorisePage( - id: model.categorise[index].id, - titleName: model.categorise[index].name, - ) - : FinalProductsPage( - id: model.categorise[index].id, - ), + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 10.0), + child: Texts( + projectViewModel.isArabic + ? model.categorise[index].namen + : model.categorise[index].name, + fontWeight: FontWeight.w600, + ), ), ), - }, - ), - ); - }, + onTap: () => { + Navigator.push( + context, + FadePage( + page: model.categorise[index].id != '12' + ? ParentCategorisePage( + id: model.categorise[index].id, + titleName: model.categorise[index].name, + ) + : FinalProductsPage( + id: model.categorise[index].id, + ), + ), + ), + }, + ), + ); + }, + ), ), ), Container( @@ -110,7 +112,7 @@ class _PharmacyCategorisePageState extends State { FadePage( page: FinalProductsPage( id: "", - productType: 4, + productType: 6, ), ), ); @@ -140,21 +142,34 @@ class _PharmacyCategorisePageState extends State { Expanded( child: Padding( padding: EdgeInsets.all(4.0), - child: Container( - height: 50.0, - width: 55.0, - decoration: BoxDecoration( - color: Colors.orangeAccent.shade200 - .withOpacity(0.34), - borderRadius: BorderRadius.circular(5.0), - ), - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 10.0), - child: Texts( - projectViewModel.isArabic - ? 'الاكثر مشاهدة' - : 'Most Viewed', - fontWeight: FontWeight.w600, + child: InkWell( + onTap: () { + Navigator.push( + context, + FadePage( + page: FinalProductsPage( + id: "", + productType: 4, + ), + ), + ); + }, + child: Container( + height: 50.0, + width: 55.0, + decoration: BoxDecoration( + color: Colors.orangeAccent.shade200 + .withOpacity(0.34), + borderRadius: BorderRadius.circular(5.0), + ), + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 10.0), + child: Texts( + projectViewModel.isArabic + ? 'الاكثر مشاهدة' + : 'Most Viewed', + fontWeight: FontWeight.w600, + ), ), ), ), @@ -167,20 +182,33 @@ class _PharmacyCategorisePageState extends State { Expanded( child: Padding( padding: EdgeInsets.all(4.0), - child: Container( - height: 50.0, - width: 55.0, - decoration: BoxDecoration( - color: Colors.blue.shade200.withOpacity(0.34), - borderRadius: BorderRadius.circular(5.0), - ), - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 10.0), - child: Texts( - projectViewModel.isArabic - ? 'منتجات جديدة' - : 'New Products', - fontWeight: FontWeight.w600, + child: InkWell( + onTap: () { + Navigator.push( + context, + FadePage( + page: FinalProductsPage( + id: "", + productType: 5, + ), + ), + ); + }, + child: Container( + height: 50.0, + width: 55.0, + decoration: BoxDecoration( + color: Colors.blue.shade200.withOpacity(0.34), + borderRadius: BorderRadius.circular(5.0), + ), + child: Padding( + padding: EdgeInsets.symmetric(horizontal: 10.0), + child: Texts( + projectViewModel.isArabic + ? 'منتجات جديدة' + : 'New Products', + fontWeight: FontWeight.w600, + ), ), ), ),