diff --git a/android/build/reports/problems/problems-report.html b/android/build/reports/problems/problems-report.html new file mode 100644 index 0000000..86595a8 --- /dev/null +++ b/android/build/reports/problems/problems-report.html @@ -0,0 +1,663 @@ + + + + + + + + + + + + + Gradle Configuration Cache + + + +
+ +
+ Loading... +
+ + + + + + diff --git a/lib/StripePayment/bloc/stripe_payment_bloc.dart b/lib/StripePayment/bloc/stripe_payment_bloc.dart index 79b166f..94bea65 100644 --- a/lib/StripePayment/bloc/stripe_payment_bloc.dart +++ b/lib/StripePayment/bloc/stripe_payment_bloc.dart @@ -58,9 +58,10 @@ class StripePaymentBloc extends Bloc { paymentIntentClientSecret: clientSecret, merchantDisplayName: "CityCards", style: ThemeMode.light, + allowsDelayedPaymentMethods: true, ), ); - + await Stripe.instance.presentPaymentSheet(); emit(const StripePaymentSheetReady()); emit(const StripePaymentLoading( @@ -105,6 +106,8 @@ class StripePaymentBloc extends Bloc { paymentIntentClientSecret: event.clientSecret, merchantDisplayName: "CityCards", style: ThemeMode.light, + allowsDelayedPaymentMethods: true, + ), ); diff --git a/lib/StripePayment/view/stripe_payment.dart b/lib/StripePayment/view/stripe_payment.dart index c62dfa0..53c2ac0 100644 --- a/lib/StripePayment/view/stripe_payment.dart +++ b/lib/StripePayment/view/stripe_payment.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; - import '../bloc/stripe_payment_bloc.dart'; import '../bloc/stripe_payment_event.dart'; import '../bloc/stripe_payment_state.dart'; diff --git a/lib/my_pass/views/pass_attraction_details_view.dart b/lib/my_pass/views/pass_attraction_details_view.dart index 50ee390..0b55b6e 100644 --- a/lib/my_pass/views/pass_attraction_details_view.dart +++ b/lib/my_pass/views/pass_attraction_details_view.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:ui'; import 'package:citycards_customer/attraction_details/widgets/share_bottomsheet.dart'; import 'package:citycards_customer/common_packages/app_bar.dart'; @@ -309,11 +310,15 @@ class _PassAttractionDetailsViewState extends State { color: Colors.white, borderRadius: BorderRadius.circular(12.r), ), - child: QrImageView( - data: - "Details:\nQR No. : ${attraction.qr.qrNumber}\nQR Code : ${attraction.qr.qrCode}\nStatus : ${attraction.qr.qrStatus}\nExpires At: ${attraction.qr.qrExpiresAt}\nChecked In: ${attraction.qr.checkedInDatetime}\nRemaining : ${attraction.qr.qrRemainingMinutes} mins\nIs Active : ${attraction.qr.isQrActive ? "Yes" : "No"}", - version: QrVersions.auto, - size: 200.w, + child: ImageFiltered( + imageFilter: _isCheckedIn + ? ImageFilter.blur(sigmaX: 0, sigmaY: 0) // clear when checked in + : ImageFilter.blur(sigmaX: 6, sigmaY: 6), // blurred before check-in + child: QrImageView( + data: "Details:\nQR No. : ${attraction.qr.qrNumber}\nQR Code : ${attraction.qr.qrCode}\nStatus : ${attraction.qr.qrStatus}\nExpires At: ${attraction.qr.qrExpiresAt}\nChecked In: ${attraction.qr.checkedInDatetime}\nRemaining : ${attraction.qr.qrRemainingMinutes} mins\nIs Active : ${attraction.qr.isQrActive ? "Yes" : "No"}", + version: QrVersions.auto, + size: 200.w, + ), ), ), SizedBox(height: 16.h), diff --git a/lib/networkApiServices/api_urls.dart b/lib/networkApiServices/api_urls.dart index 2e1ee15..67fb456 100644 --- a/lib/networkApiServices/api_urls.dart +++ b/lib/networkApiServices/api_urls.dart @@ -1,8 +1,8 @@ class ApiUrls { // static const baseUrl = "https://devapi.citycards.betadelivery.com";//Normal API - static const baseUrl = "https://testingapi.citycards.betadelivery.com";// Test API - // static const baseUrl = "https://uatapi.citycard.betadelivery.com";// Production Lvl API + // static const baseUrl = "https://testingapi.citycards.betadelivery.com";// Test API + static const baseUrl = "https://uatapi.citycard.betadelivery.com";// Production Lvl API static const refreshToken = "$baseUrl/auth/refresh"; diff --git a/lib/postcard/views/postcard_checkout_page_view.dart b/lib/postcard/views/postcard_checkout_page_view.dart index 10128b5..1e8c1cf 100644 --- a/lib/postcard/views/postcard_checkout_page_view.dart +++ b/lib/postcard/views/postcard_checkout_page_view.dart @@ -5,6 +5,7 @@ import 'package:citycards_customer/postcard/widgets/front_card_widget.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:flutter_stripe/flutter_stripe.dart'; import 'package:google_fonts/google_fonts.dart'; import '../../StripePayment/bloc/stripe_payment_bloc.dart'; import '../../StripePayment/bloc/stripe_payment_event.dart'; @@ -128,251 +129,105 @@ class _PostcardCheckoutPageViewState extends State { /// 🆕 Handle payment flow with client secret Future _handlePaymentFlow(BuildContext context, String clientSecret) async { - // Show payment bottom sheet with BLoC - final paymentSuccess = await showModalBottomSheet( - context: context, - isDismissible: false, - enableDrag: false, - isScrollControlled: true, - backgroundColor: Colors.transparent, - builder: (bottomSheetContext) { - return BlocProvider( - create: (_) => StripePaymentBloc(stripeService: StripeService()) - ..add(InitiatePaymentWithClientSecret(clientSecret: clientSecret)), - child: BlocConsumer( - listener: (context, state) { - if (state is StripePaymentSuccess) { - Navigator.of(bottomSheetContext).pop(true); - } else if (state is StripePaymentFailure || state is StripePaymentCancelled) { - Navigator.of(bottomSheetContext).pop(false); - } - }, - builder: (context, state) { - return Container( - height: MediaQuery.of(context).size.height * 0.5, - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.only( - topLeft: Radius.circular(20), - topRight: Radius.circular(20), - ), - ), - child: Center( - child: Padding( - padding: const EdgeInsets.all(24.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (state is StripePaymentLoading) ...[ - const CircularProgressIndicator( - color: Color(0xffF95F62), - strokeWidth: 3, - valueColor: AlwaysStoppedAnimation( - Color(0xFFF95F62), - ), - ), - const SizedBox(height: 24), - const Text( - "Processing payment...", - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Color(0xFF333333), - ), - ), - ] else if (state is StripePaymentSuccess) ...[ - const Icon( - Icons.check_circle, - color: Colors.green, - size: 64, - ), - const SizedBox(height: 16), - const Text( - "Payment Successful!", - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Color(0xFF333333), - ), - ), - ] else if (state is StripePaymentFailure) ...[ - const Icon( - Icons.error, - color: Colors.red, - size: 64, - ), - const SizedBox(height: 16), - const Text( - "Payment Failed", - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Color(0xFF333333), - ), - ), - const SizedBox(height: 8), - Text( - state.error, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - color: Colors.grey[600], - ), - ), - ] else if (state is StripePaymentCancelled) ...[ - const Icon( - Icons.cancel, - color: Colors.orange, - size: 64, - ), - const SizedBox(height: 16), - const Text( - "Payment Cancelled", - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: Color(0xFF333333), - ), - ), - ], - const SizedBox(height: 32), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 24, - vertical: 16, - ), - decoration: BoxDecoration( - color: const Color(0xFFF5F5F5), - borderRadius: BorderRadius.circular(12), - border: Border.all( - color: const Color(0xFFE0E0E0), - ), - ), - child: Column( - children: [ - Text( - "Payment Amount", - style: TextStyle( - fontSize: 14, - color: Colors.grey[600], - ), - ), - const SizedBox(height: 8), - Text( - "\$${widget.totalAmount.toStringAsFixed(2)}", - style: const TextStyle( - fontSize: 32, - fontWeight: FontWeight.bold, - color: Color(0xFF333333), - ), - ), - ], - ), - ), - const SizedBox(height: 24), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.lock_outline, - size: 16, - color: Colors.grey[600], - ), - const SizedBox(width: 6), - Text( - "Secured by Stripe", - style: TextStyle( - fontSize: 12, - color: Colors.grey[600], - ), - ), - ], - ), - ], - ), - ), - ), - ); - }, + try { + // Step 1: Initialize Stripe's native payment sheet + await Stripe.instance.initPaymentSheet( + paymentSheetParameters: SetupPaymentSheetParameters( + paymentIntentClientSecret: clientSecret, + merchantDisplayName: 'CityCards', + allowsDelayedPaymentMethods: true, // ← enables UPI, netbanking, etc. + style: ThemeMode.light, + ), + ); + + // Step 2: Present Stripe's native UI (card, UPI, wallets, etc.) + await Stripe.instance.presentPaymentSheet(); + + // Step 3: Payment succeeded + if (!mounted) return; + _onPaymentSuccess(context); + + } on StripeException catch (e) { + if (!mounted) return; + if (e.error.code == FailureCode.Canceled) { + _onPaymentCancelled(context); + } else { + _onPaymentFailed(context, e.error.message ?? 'Payment failed'); + } + } catch (e) { + if (!mounted) return; + _onPaymentFailed(context, e.toString()); + } + } + + void _onPaymentSuccess(BuildContext context) { + context.read().add(CheckLoginStatus()); + + if (widget.isEditMode) { + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => OrderSuccessPageView( + isEditMode: true, + isCartMode: widget.isCartMode, + pcImage: widget.pcImage, + pcContent: widget.pcContent, + pcState: widget.stateName, + pcCountry: widget.countryName, + pcCity: widget.cityName, + pcZipCode: widget.zipCode, + pcName: widget.fullname, + pcAddress: widget.address1, + senderName: widget.senderName, + senderCity: widget.senderCity, + senderCountry: widget.senderCountry, ), - ); - }, + ), + ); + context.read().add( + ConfirmPaymentEvent( + stripeStatus: 'succeeded', + paymentStatus: 'success', + ), + ); + } else { + context.read().add(GoToNextStep()); + context.read().add( + ConfirmPaymentEvent( + stripeStatus: 'succeeded', + paymentStatus: 'success', + ), + ); + } + } + + void _onPaymentCancelled(BuildContext context) { + // User dismissed the sheet — just save draft if in edit mode + if (widget.isEditMode) { + context.read().add(SaveAsDraftEvent()); + context.read().add( + UpdateCheckoutDataEvent( + postcardId: widget.postcardId, + ), + ); + } + } + + void _onPaymentFailed(BuildContext context, String error) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Payment failed: $error'), + backgroundColor: Colors.red, + ), ); - // Handle payment result - if (!mounted) return; - - if (paymentSuccess == true) { - context.read().add(CheckLoginStatus()); - if (widget.isEditMode) { - // For edit mode, navigate directly to OrderSuccessPageView - Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) => OrderSuccessPageView( - isEditMode: true, - isCartMode: widget.isCartMode, - // Front - pcImage: widget.pcImage, - // Back - pcContent: widget.pcContent, - pcState: widget.stateName, - pcCountry: widget.countryName, - pcCity: widget.cityName, - pcZipCode: widget.zipCode, - pcName: widget.fullname, - pcAddress: widget.address1, - senderName: widget.senderName, - senderCity: widget.senderCity, - senderCountry: widget.senderCountry, - ), - ), - ); - final bloc = context.read(); - bloc.add( - ConfirmPaymentEvent( - stripeStatus: 'succeeded', - paymentStatus: 'success', - ), - ); - } else { - // For new orders, use the normal step flow - context.read().add(GoToNextStep()); - final bloc = context.read(); - bloc.add( - ConfirmPaymentEvent( - stripeStatus: 'succeeded', - paymentStatus: 'success', - ), - ); - } - - } else { - if (widget.isEditMode) { - context.read().add(SaveAsDraftEvent()); - context.read().add( - UpdateCheckoutDataEvent( - postcardId: widget.postcardId, // pass the id from widget - ), - ); - } - - // Payment failed or cancelled - go to MyPostCardsView - // Navigator.pushReplacement( - // context, - // MaterialPageRoute( - // builder: (context) => const MyPostCardsView(), - // ), - // ); - - - // final bloc = context.read(); - // bloc.add( - // ConfirmPaymentEvent( - // stripeStatus: 'requires_payment_method', - // paymentStatus: 'failed', - // ), - // ); + if (widget.isEditMode) { + context.read().add(SaveAsDraftEvent()); + context.read().add( + UpdateCheckoutDataEvent( + postcardId: widget.postcardId, + ), + ); } } diff --git a/lib/postcard/views/write_message_step_page_view.dart b/lib/postcard/views/write_message_step_page_view.dart index 457f95f..deb43da 100644 --- a/lib/postcard/views/write_message_step_page_view.dart +++ b/lib/postcard/views/write_message_step_page_view.dart @@ -48,7 +48,7 @@ class _WriteMessageStepPageViewState extends State { TextPosition(offset: _controller.text.length)); final fonts = [ - {"name": "Default", "font": GoogleFonts.caveat(), "cleanName": "Caveat"}, + {"name": "Default", "font": GoogleFonts.poppins(), "cleanName": "Poppins"}, {"name": "Patrick Hand", "font": GoogleFonts.patrickHand(), "cleanName": "Patrick Hand"}, {"name": "Indie Flower", "font": GoogleFonts.indieFlower(), "cleanName": "Indie Flower"}, {"name": "Gloria Hallelujah", "font": GoogleFonts.gloriaHallelujah(), "cleanName": "Gloria Hallelujah"}, diff --git a/pubspec.lock b/pubspec.lock index ed38889..3e0ff52 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -9,6 +9,38 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" + app_links: + dependency: "direct main" + description: + name: app_links + sha256: "3462d9defc61565fde4944858b59bec5be2b9d5b05f20aed190adb3ad08a7abc" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + app_links_linux: + dependency: transitive + description: + name: app_links_linux + sha256: f5f7173a78609f3dfd4c2ff2c95bd559ab43c80a87dc6a095921d96c05688c81 + url: "https://pub.dev" + source: hosted + version: "1.0.3" + app_links_platform_interface: + dependency: transitive + description: + name: app_links_platform_interface + sha256: "05f5379577c513b534a29ddea68176a4d4802c46180ee8e2e966257158772a3f" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + app_links_web: + dependency: transitive + description: + name: app_links_web + sha256: af060ed76183f9e2b87510a9480e56a5352b6c249778d07bd2c95fc35632a555 + url: "https://pub.dev" + source: hosted + version: "1.0.4" archive: dependency: transitive description: @@ -597,6 +629,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.8" + gtk: + dependency: transitive + description: + name: gtk + sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c + url: "https://pub.dev" + source: hosted + version: "2.1.0" html: dependency: transitive description: @@ -1588,4 +1628,4 @@ packages: version: "3.1.3" sdks: dart: ">=3.10.0 <4.0.0" - flutter: ">=3.38.0" + flutter: ">=3.38.1" diff --git a/pubspec.yaml b/pubspec.yaml index 7fda351..7dd4708 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -71,6 +71,7 @@ dependencies: libphonenumber_plugin: ^0.3.3 phone_numbers_parser: ^9.0.20 qr_flutter: ^4.1.0 + app_links: ^7.0.0 dev_dependencies: flutter_test: