-
Notifications
You must be signed in to change notification settings - Fork 125
/
pay.dart
100 lines (85 loc) · 3.79 KB
/
pay.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/// Copyright 2023 Google LLC.
/// SPDX-License-Identifier: Apache-2.0
part of '../pay.dart';
/// List of supported payment providers and platform pairs.
const supportedProviders = {
TargetPlatform.android: [PayProvider.google_pay],
TargetPlatform.iOS: [PayProvider.apple_pay],
};
/// High level layer to easily manage cross-platform integrations.
///
/// This class simplifies using the plugin and abstracts platform-specific
/// directives.
/// To use it, instantiate it with a list of configurations for the payment
/// providers supported:
/// ```dart
/// final payClient = Pay.withAssets(paymentConfigurationAssets)
/// await payClient.showPaymentSelector(paymentItems: paymentItems);
/// ```
class Pay {
/// The implementation of the platform interface to talk to the native ends.
final PayPlatform _payPlatform;
/// Map of configurations for the payment providers targeted.
Map<PayProvider, PaymentConfiguration>? _configurations;
// Future to keep track of asynchronous initialization items.
Future<void>? _assetInitializationFuture;
/// Creates an instance with a dictionary of [_configurations] and
/// instantiates the [_payPlatform] to communicate with the native platforms.
Pay(this._configurations) : _payPlatform = PayMethodChannel();
/// Alternative constructor to create a [Pay] object with a list of
/// configurations in [String] format.
@Deprecated(
'Prefer to use [Pay({ [PayProvider]: [PaymentConfiguration] })]. Take a look at the readme to see examples')
Pay.withAssets(List<String> configAssets)
: _payPlatform = PayMethodChannel() {
_assetInitializationFuture = _loadConfigAssets(configAssets);
}
/// Load the list of configurations from the assets.
Future<void> _loadConfigAssets(List<String> configurationAssets) async =>
_configurations = Map.fromEntries(await Future.wait(configurationAssets
.map((ca) => PaymentConfiguration.fromAsset(ca))
.map((c) async => MapEntry(((await c).provider), await c))));
/// Determines whether a user can pay with the selected [provider].
///
/// This method wraps the [userCanPay] method in the platform interface. It
/// makes sure that the [provider] exists and is available in the platform
/// running the logic.
Future<bool> userCanPay(PayProvider provider) async {
await throwIfProviderIsNotDefined(provider);
if (supportedProviders[defaultTargetPlatform]!.contains(provider)) {
return _payPlatform.userCanPay(_configurations![provider]!);
}
return Future.value(false);
}
/// Shows the payment selector to initiate a payment process.
///
/// This method wraps the [showPaymentSelector] method in the platform
/// interface, and opens the payment selector for the [provider] of choice,
/// with the [paymentItems] in the price summary.
Future<Map<String, dynamic>> showPaymentSelector(
PayProvider provider,
List<PaymentItem> paymentItems,
) async {
await throwIfProviderIsNotDefined(provider);
return _payPlatform.showPaymentSelector(
_configurations![provider]!, paymentItems);
}
/// Verifies that the selected provider has been previously configured or
/// throws otherwise.
Future<void> throwIfProviderIsNotDefined(PayProvider provider) async {
await _assetInitializationFuture;
if (!_configurations!.containsKey(provider)) {
throw ProviderNotConfiguredException(
'No configuration has been provided for the provider ($provider)');
}
}
}
/// Thrown to indicate that the configuration for a request provider has not
/// been provided.
class ProviderNotConfiguredException implements Exception {
ProviderNotConfiguredException(this.message);
/// A human-readable error message, possibly null.
final String? message;
@override
String toString() => 'ProviderNotConfiguredException: $message';
}