diff --git a/CHANGELOG.md b/CHANGELOG.md index c2a96b0..7f78dd5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.0.1 + +- Remove Get Payment Method +- update package screenshot desc + ## 2.0.0 - Update Package UI diff --git a/assets/images/test.png b/assets/images/test.png index 6636c90..9b59cb4 100644 Binary files a/assets/images/test.png and b/assets/images/test.png differ diff --git a/example/lib/payment_success_dialog.dart b/example/lib/payment_success_dialog.dart index f687cd6..6b69b10 100644 --- a/example/lib/payment_success_dialog.dart +++ b/example/lib/payment_success_dialog.dart @@ -21,7 +21,7 @@ Future showPaymentSuccessDialog( content: Column( mainAxisSize: MainAxisSize.min, children: [ - Icon( + const Icon( Icons.check_circle, color: Colors.green, size: 64, diff --git a/example/pubspec.lock b/example/pubspec.lock index 7152e05..e31cd2f 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -275,7 +275,7 @@ packages: path: ".." relative: true source: path - version: "1.0.12" + version: "2.0.1" nested: dependency: transitive description: diff --git a/lib/src/models/payment_success.dart b/lib/src/models/payment_success.dart index 2271f79..15ffece 100644 --- a/lib/src/models/payment_success.dart +++ b/lib/src/models/payment_success.dart @@ -5,6 +5,11 @@ import 'package:moosyl/moosyl.dart'; /// Normalizes [PaymentGetData] and [PostPayment200Response] into a common shape /// for display in the success dialog and for [onPaymentSuccess] callback. class PaymentSuccess { + /// Creates a new [PaymentSuccess] instance. + /// + /// * [id]: The ID of the payment. + /// * [amount]: The amount of the payment. + /// * [status]: The status of the payment. const PaymentSuccess({ required this.id, required this.amount, @@ -21,11 +26,11 @@ class PaymentSuccess { final String status; /// Creates from [PaymentGetData] (Sedad - from getPayment). - factory PaymentSuccess.fromPaymentGetData(PaymentGetData data) { + factory PaymentSuccess.fromPaymentRequestGetData(PaymentRequestGetData data) { return PaymentSuccess( id: data.id, amount: data.amount, - status: data.status.name, + status: 'completed', ); } diff --git a/lib/src/models/selection_error.dart b/lib/src/models/selection_error.dart index c160a26..bea99fb 100644 --- a/lib/src/models/selection_error.dart +++ b/lib/src/models/selection_error.dart @@ -26,7 +26,11 @@ enum SelectionErrorType { } } +/// Extension methods for [SelectionErrorType] to provide string messages. extension SelectionErrorTypeExtension on SelectionErrorType { + /// Returns the string message for the selection error type. + /// + /// * [l10n]: The localization object to get the message from. String message(MoosylLocalization l10n) { switch (this) { case SelectionErrorType.paymentRequestFullyPaid: diff --git a/lib/src/pages/bankily_view.dart b/lib/src/pages/bankily_view.dart index 54f476f..f4be9d4 100644 --- a/lib/src/pages/bankily_view.dart +++ b/lib/src/pages/bankily_view.dart @@ -16,6 +16,14 @@ import 'package:provider/provider.dart'; /// A widget that represents the Bankily payment process. class BankilyView extends StatelessWidget { + /// Creates a new [BankilyView] instance. + /// + /// * [method]: The payment method to use. + /// * [publishableApiKey]: The publishable API key to use. + /// * [transactionId]: The transaction ID to use. + /// * [onPaymentSuccess]: The callback to call when the payment is successful. + /// * [onClose]: The callback to call when the payment is closed. + /// * [paymentCodeDisplay]: The code to display. const BankilyView({ super.key, required this.method, @@ -26,11 +34,22 @@ class BankilyView extends StatelessWidget { required this.paymentCodeDisplay, }); + /// The payment method to use. final ConfigurationListDataInner method; + + /// The publishable API key to use. final String publishableApiKey; + + /// The transaction ID to use. final String transactionId; + + /// The callback to call when the payment is successful. final FutureOr Function()? onPaymentSuccess; + + /// The callback to call when the payment is closed. final VoidCallback? onClose; + + /// The code to display. final String? paymentCodeDisplay; @override diff --git a/lib/src/pages/home.dart b/lib/src/pages/home.dart index e0e01ab..6cd5409 100644 --- a/lib/src/pages/home.dart +++ b/lib/src/pages/home.dart @@ -3,7 +3,6 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; -import 'package:moosyl_flutter/src/models/payment_method_model.dart'; import 'package:moosyl_flutter/src/models/payment_success.dart'; import 'package:moosyl_flutter/src/pages/moosyl_view.dart'; @@ -20,10 +19,6 @@ class Moosyl extends HookWidget { /// [open] is the callback to open the payment sheet. final Widget Function(VoidCallback open)? inputBuilder; - /// Optional map to provide custom icons for each payment method type. - /// The keys are [PaymentMethodTypes] and the values are the paths to the custom icons. - final Map? customIcons; - /// Optional callback to be triggered upon successful payment with [PaymentSuccess]. final FutureOr Function(PaymentSuccess payment)? onPaymentSuccess; @@ -35,14 +30,12 @@ class Moosyl extends HookWidget { /// * [context]: The build context. /// * [publishableApiKey]: The API key to authenticate the payment. /// * [transactionId]: The transaction ID for the current session. - /// * [customIcons]: Map for custom icons for payment methods. /// * [onPaymentSuccess]: Callback for when payment is successful. static void show( BuildContext context, { required String publishableApiKey, required String transactionId, final FutureOr Function(PaymentSuccess payment)? onPaymentSuccess, - Map? customIcons, bool isFullPage = false, }) { showBarModalBottomSheet( @@ -60,14 +53,12 @@ class Moosyl extends HookWidget { /// /// * [publishableApiKey]: The API key for payment authentication. /// * [transactionId]: The transaction ID for the current payment session. - /// * [customIcons]: Optional custom icons for specific payment methods. /// * [inputBuilder]: A function to build a custom input widget. /// * [onPaymentSuccess]: Callback when the payment is successful. const Moosyl({ super.key, required this.publishableApiKey, required this.transactionId, - this.customIcons, this.inputBuilder, this.onPaymentSuccess, this.isFullPage = false, diff --git a/lib/src/pages/masrivi_view.dart b/lib/src/pages/masrivi_view.dart index 3dc568a..d069f05 100644 --- a/lib/src/pages/masrivi_view.dart +++ b/lib/src/pages/masrivi_view.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:moosyl_flutter/src/models/payment_success.dart'; -import 'package:moosyl_flutter/src/services/pay_service.dart'; +import 'package:moosyl_flutter/src/services/get_payment_request_service.dart'; import 'package:webview_flutter/webview_flutter.dart'; /// Base URL for Masrivi payment web view. @@ -14,6 +14,14 @@ const String _masriviPayBaseUrl = 'https://payments.moosyl.com/masrivi/pay'; /// When the URL contains "/success", [onPaymentSuccess] is invoked. /// When the URL contains "/decline", [onPaymentDeclined] is invoked and the view goes back. class MasriviView extends StatelessWidget { + /// Creates a new [MasriviView] instance. + /// + /// * [publishableApiKey]: The API key for authenticating the payment. + /// * [transactionId]: The transaction ID for the payment. + /// * [configurationId]: The configuration ID (payment method ID) from [PaymentMethod.id]. + /// * [onPaymentSuccess]: The callback to call when the payment is successful. + /// * [onBackPress]: The callback to call when the back button is pressed. + /// * [onPaymentDeclined]: The callback to call when the payment is declined. const MasriviView({ super.key, required this.publishableApiKey, @@ -123,9 +131,10 @@ class _MasriviWebViewState extends State<_MasriviWebView> { final onSuccess = widget.onPaymentSuccess; if (onSuccess == null) return; try { - final paymentData = await PayService(widget.publishableApiKey) - .getPayment(transactionId: widget.transactionId); - final payment = PaymentSuccess.fromPaymentGetData(paymentData); + final paymentData = + await GetPaymentRequestService(widget.publishableApiKey) + .get(widget.transactionId); + final payment = PaymentSuccess.fromPaymentRequestGetData(paymentData); await onSuccess(payment); } catch (_) { await onSuccess(PaymentSuccess( diff --git a/lib/src/pages/payment_methods_view.dart b/lib/src/pages/payment_methods_view.dart index 5ebe82e..edc78ea 100644 --- a/lib/src/pages/payment_methods_view.dart +++ b/lib/src/pages/payment_methods_view.dart @@ -132,23 +132,29 @@ class _SelectPaymentMethodContent extends StatelessWidget { padding: const EdgeInsets.all(16), border: Border.all(color: Colors.grey.shade300), borderRadius: BorderRadius.circular(8), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - mainAxisSize: MainAxisSize.min, - spacing: 8, - children: [ - Text(localizationHelper.chooseHowYouWouldLikeToPay, - style: textTheme.titleMedium), - const SizedBox(height: 10), - ...methods.asMap().entries.map((e) { - final method = e.value; - return _MethodRow( - method: method, - isSelected: pendingSelection?.id == method.id, - onTap: () => provider.setPendingSelection(method), - ); - }), - ], + child: RadioGroup( + groupValue: pendingSelection, + onChanged: (value) { + if (value != null) provider.setPendingSelection(value); + }, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + spacing: 8, + children: [ + Text(localizationHelper.chooseHowYouWouldLikeToPay, + style: textTheme.titleMedium), + const SizedBox(height: 10), + ...methods.asMap().entries.map((e) { + final method = e.value; + return _MethodRow( + method: method, + isSelected: pendingSelection?.id == method.id, + onTap: () => provider.setPendingSelection(method), + ); + }), + ], + ), ), ), ], @@ -488,7 +494,6 @@ class _MethodRow extends StatelessWidget { @override Widget build(BuildContext context) { - final provider = context.watch(); final localizationHelper = MoosylLocalization.of(context)!; final textTheme = Theme.of(context).textTheme; final primaryColor = Theme.of(context).colorScheme.primary; @@ -541,10 +546,7 @@ class _MethodRow extends StatelessWidget { // Radio Radio( value: method, - groupValue: provider.pendingSelection, - onChanged: (_) => onTap(), - fillColor: MaterialStateProperty.all(primaryColor), - activeColor: primaryColor, + fillColor: WidgetStateProperty.all(primaryColor), ), ], ), diff --git a/lib/src/pages/sedad_view.dart b/lib/src/pages/sedad_view.dart index 23be590..391c4ea 100644 --- a/lib/src/pages/sedad_view.dart +++ b/lib/src/pages/sedad_view.dart @@ -24,6 +24,11 @@ class SedadView extends StatelessWidget { /// Callback when the dialog is closed (e.g. to go back to payment method selection). final VoidCallback? onClose; + /// Creates a new [SedadView] instance. + /// + /// * [paymentCodeDisplay]: The code to display. + /// * [paymentRequest]: The payment request containing amount and other details. + /// * [onClose]: The callback to call when the dialog is closed. const SedadView({ super.key, required this.paymentCodeDisplay, diff --git a/lib/src/providers/pay_provider.dart b/lib/src/providers/pay_provider.dart index 63ff269..34cd818 100644 --- a/lib/src/providers/pay_provider.dart +++ b/lib/src/providers/pay_provider.dart @@ -168,7 +168,7 @@ class PayProvider extends ChangeNotifier { notifyListeners(); final result = await ErrorHandlers.catchErrors( - () => service.getPayment(transactionId: transactionId), + () => GetPaymentRequestService(publishableApiKey).get(transactionId), ); if (result.isError) { @@ -177,8 +177,8 @@ class PayProvider extends ChangeNotifier { } isLoading = false; - if (result.result!.status.name == 'completed') { - final payment = PaymentSuccess.fromPaymentGetData(result.result!); + if (result.result!.amount == 0) { + final payment = PaymentSuccess.fromPaymentRequestGetData(result.result!); onBeforePaymentSuccess?.call(); onPaymentSuccess?.call(payment); } else { diff --git a/lib/src/services/pay_service.dart b/lib/src/services/pay_service.dart index 1b5646c..85cdbc7 100644 --- a/lib/src/services/pay_service.dart +++ b/lib/src/services/pay_service.dart @@ -57,21 +57,4 @@ class PayService { client.setApiKey('ApiKey', publishableApiKey); return client; } - - /// Fetches a payment by its ID. - /// - /// Makes an API call via [PaymentApi] to retrieve the payment. - /// Returns a [PaymentGet] object containing the payment details. - Future getPayment({ - required String transactionId, - }) async { - final client = _createClient(); - final paymentApi = client.getPaymentApi(); - final response = await paymentApi.getPaymentById(id: transactionId); - final data = response.data; - if (data == null) { - throw StateError('payment request not found'); - } - return data.data; - } } diff --git a/lib/src/widgets/buttons.dart b/lib/src/widgets/buttons.dart index c4652a4..2471624 100644 --- a/lib/src/widgets/buttons.dart +++ b/lib/src/widgets/buttons.dart @@ -65,15 +65,15 @@ class AppButton extends StatelessWidget { if (_isDisabled) { bg = surface; - fg = onSurface.withOpacity(0.6); - side = BorderSide(color: outlineColor.withOpacity(0.5)); + fg = onSurface.withValues(alpha: 0.6); + side = BorderSide(color: outlineColor.withValues(alpha: 0.5)); } else if (style == AppButtonStyle.outline) { bg = Colors.transparent; - fg = this.textColor ?? primary; + fg = textColor ?? primary; side = border == BorderSide.none ? BorderSide(color: primary) : border; } else { // primary - bg = this.background ?? primary; + bg = background ?? primary; fg = textColor ?? onPrimary; side = border; } diff --git a/pubspec.yaml b/pubspec.yaml index 2df7bfc..49bc45b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: moosyl_flutter description: "The Moosyl Flutter SDK is a powerful tool for integrating payment solutions with Mauritania's popular banking apps, such as Bankily, Sedad, and Masrivi" homepage: https://github.com/SoftwareSavants/moosyl_flutter -version: 2.0.0 +version: 2.0.1 license: MIT