Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e7c6bae
Refactor project structure by renaming 'moosyl' to 'moosyl_flutter' i…
eminos-sd Feb 27, 2026
5e73417
Refactor README and codebase by renaming 'moosyl' to 'moosyl_flutter'…
eminos-sd Feb 27, 2026
d236eff
Refactor payment components by removing organization logo references …
eminos-sd Feb 27, 2026
29ceb3a
Update README to clarify package name from 'Moosyl' to 'Moosyl Flutte…
eminos-sd Feb 27, 2026
c560171
Add `onBackPress` event handler to README for MoosylView configuration
eminos-sd Feb 27, 2026
1a9e1f0
Remove outdated transactionId reference from README to streamline pay…
eminos-sd Feb 27, 2026
6ee2603
Update dependencies and localization strings, refactor payment method…
eminos-sd Feb 27, 2026
725dbac
Enhance payment flow by adding optional payment code display in Banki…
eminos-sd Feb 28, 2026
af63ff1
Refactor payment flow to include optional callback before payment suc…
eminos-sd Feb 28, 2026
cc09972
Refactor payment dialog to utilize a callback for handling actions be…
eminos-sd Feb 28, 2026
9a77149
Remove customIcons parameter from Moosyl and MoosylView classes, simp…
eminos-sd Mar 2, 2026
2337677
Refactor payment components to remove primaryColor parameter from mul…
eminos-sd Mar 2, 2026
60bb8ce
Add localization for payment completion errors in Arabic, English, an…
eminos-sd Mar 2, 2026
a0bd1ef
Enhance selection error handling by adding a new error type for incom…
eminos-sd Mar 2, 2026
3857c23
Implement error handling for incomplete payments in PayProvider and d…
eminos-sd Mar 2, 2026
9483f94
Integrate payment success dialog and model into the payment flow. Upd…
eminos-sd Mar 2, 2026
1ab6b72
Refactor payment flow to utilize MoosylFlutter for opening payment di…
eminos-sd Mar 2, 2026
6df4eff
Update README to reflect SDK name change to Moosyl Flutter, enhance p…
eminos-sd Mar 2, 2026
bdb7333
Add handling for cancel URL in MasriviWebView and update payment meth…
eminos-sd Mar 2, 2026
469af9c
Enhance localization by adding payment failure and decline messages i…
eminos-sd Mar 2, 2026
2d36ecc
Add 'try again' messages in Arabic, English, and French localization …
eminos-sd Mar 2, 2026
3d45c7e
Add 'unknown' error type to SelectionErrorType enum and update error …
eminos-sd Mar 2, 2026
69fa1e5
Update CHANGELOG for version 2.0.0: introduce `MoosylFlutter.show()` …
eminos-sd Mar 2, 2026
160388c
Refactor README to simplify payment flow instructions for `MoosylFlut…
eminos-sd Mar 2, 2026
fba8387
Update CHANGELOG to reflect the addition of the Package UI update and…
eminos-sd Mar 2, 2026
c4d6c7b
Update version to 2.0.1 in pubspec.yaml, modify payment handling to u…
eminos-sd Mar 16, 2026
284dd6a
Merge remote-tracking branch 'origin/main' into trunk
eminos-sd Mar 16, 2026
8215613
Update version to 2.0.1 in pubspec.lock, enhance documentation with c…
eminos-sd Mar 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 2.0.1

- Remove Get Payment Method
- update package screenshot desc

## 2.0.0

- Update Package UI
Expand Down
Binary file modified assets/images/test.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion example/lib/payment_success_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Future<void> showPaymentSuccessDialog(
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
const Icon(
Icons.check_circle,
color: Colors.green,
size: 64,
Expand Down
2 changes: 1 addition & 1 deletion example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ packages:
path: ".."
relative: true
source: path
version: "1.0.12"
version: "2.0.1"
nested:
dependency: transitive
description:
Expand Down
9 changes: 7 additions & 2 deletions lib/src/models/payment_success.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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',
);
}

Expand Down
4 changes: 4 additions & 0 deletions lib/src/models/selection_error.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
19 changes: 19 additions & 0 deletions lib/src/pages/bankily_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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<void> Function()? onPaymentSuccess;

/// The callback to call when the payment is closed.
final VoidCallback? onClose;

/// The code to display.
final String? paymentCodeDisplay;

@override
Expand Down
9 changes: 0 additions & 9 deletions lib/src/pages/home.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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<PaymentMethodTypes, String>? customIcons;

/// Optional callback to be triggered upon successful payment with [PaymentSuccess].
final FutureOr<void> Function(PaymentSuccess payment)? onPaymentSuccess;

Expand All @@ -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<void> Function(PaymentSuccess payment)? onPaymentSuccess,
Map<PaymentMethodTypes, String>? customIcons,
bool isFullPage = false,
}) {
showBarModalBottomSheet(
Expand All @@ -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,
Expand Down
17 changes: 13 additions & 4 deletions lib/src/pages/masrivi_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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,
Expand Down Expand Up @@ -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(
Expand Down
46 changes: 24 additions & 22 deletions lib/src/pages/payment_methods_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<ConfigurationListDataInner>(
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),
);
}),
],
),
),
),
],
Expand Down Expand Up @@ -488,7 +494,6 @@ class _MethodRow extends StatelessWidget {

@override
Widget build(BuildContext context) {
final provider = context.watch<GetPaymentMethodsProvider>();
final localizationHelper = MoosylLocalization.of(context)!;
final textTheme = Theme.of(context).textTheme;
final primaryColor = Theme.of(context).colorScheme.primary;
Expand Down Expand Up @@ -541,10 +546,7 @@ class _MethodRow extends StatelessWidget {
// Radio
Radio<ConfigurationListDataInner>(
value: method,
groupValue: provider.pendingSelection,
onChanged: (_) => onTap(),
fillColor: MaterialStateProperty.all(primaryColor),
activeColor: primaryColor,
fillColor: WidgetStateProperty.all(primaryColor),
),
],
),
Expand Down
5 changes: 5 additions & 0 deletions lib/src/pages/sedad_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 3 additions & 3 deletions lib/src/providers/pay_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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 {
Expand Down
17 changes: 0 additions & 17 deletions lib/src/services/pay_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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<PaymentGetData> 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;
}
}
8 changes: 4 additions & 4 deletions lib/src/widgets/buttons.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Loading