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: