:drunk: Wrote some useless code

This commit is contained in:
2026-01-18 14:16:29 +08:00
parent 639417e952
commit a39853ba5a
14 changed files with 275 additions and 65 deletions

View File

@@ -12,13 +12,13 @@ Payment API (`lib/modular/api/payment.dart`) provides a simple interface for min
import 'package:island/modular/api/payment.dart';
// Get singleton instance
final paymentAPI = PaymentAPI.instance;
final paymentApi = PaymentApi.instance;
```
### Creating a Payment Order
```dart
final order = await paymentAPI.createOrder(
final order = await paymentApi.createOrder(
CreateOrderRequest(
amount: 1000, // $10.00 in cents
currency: 'USD',
@@ -35,7 +35,7 @@ final orderId = order.id;
### Processing Payment with Overlay
```dart
final result = await paymentAPI.processPaymentWithOverlay(
final result = await paymentApi.processPaymentWithOverlay(
context: context,
createOrderRequest: CreateOrderRequest(
amount: 1000,
@@ -55,7 +55,7 @@ if (result.success) {
### Processing Existing Payment
```dart
final result = await paymentAPI.processPaymentWithOverlay(
final result = await paymentApi.processPaymentWithOverlay(
context: context,
request: PaymentRequest(
orderId: 'order_123',
@@ -71,7 +71,7 @@ final result = await paymentAPI.processPaymentWithOverlay(
### Processing Payment Without Overlay (Direct)
```dart
final result = await paymentAPI.processDirectPayment(
final result = await paymentApi.processDirectPayment(
PaymentRequest(
orderId: 'order_123',
amount: 1000,
@@ -300,33 +300,106 @@ class MiniAppPayment extends StatelessWidget {
## Integration with flutter_eval
To expose this API to mini-apps loaded via flutter_eval:
### Current Status
1. Add to plugin registry:
**FlutterEval Plugin Initialization: ✅ Complete**
- `flutterEvalPlugin` is properly initialized in `lib/modular/miniapp_loader.dart`
- Initialized from `main()` during app startup
- Plugin is shared between `miniapp_loader.dart` and `lib/modular/registry.dart`
- Runtime adds plugin when loading miniapps: `runtime.addPlugin(flutterEvalPlugin)`
**PaymentBridgePlugin: ✅ Created but not yet registered**
- Located at `lib/modular/api/payment_bridge.dart`
- Provides simplified wrapper around PaymentApi
- Designed for easier integration with eval bridge
**Full Eval Bridge: ⚠️ Requires Additional Setup**
To expose PaymentApi to miniapps through eval, you need to:
1. **Create EvalPlugin Implementation**
```dart
// In a new file: lib/modular/api/payment_eval_plugin.dart
import 'package:dart_eval/dart_eval_bridge.dart';
import 'package:island/modular/api/payment.dart';
import 'package:island/modular/api/payment_bridge.dart';
class PaymentEvalPlugin implements EvalPlugin {
@override
String get identifier => 'package:island/modular/api/payment.dart';
@override
void configureForCompile(BridgeDeclarationRegistry registry) {
// Define bridge classes for PaymentRequest, PaymentResult, CreateOrderRequest
// Requires using @Bind() annotations or manual bridge definition
}
@override
void configureForRuntime(Runtime runtime) {
// Register functions that miniapps can call
// This requires bridge wrapper classes to be generated or created manually
}
}
```
2. **Generate or Create Bridge Code**
- Option A: Use `dart_eval_annotation` package with `@Bind()` annotations
- Add annotations to PaymentApi classes
- Run `dart run build_runner build` to generate bridge code
- Option B: Manually create bridge wrapper classes
- Define `$PaymentRequest`, `$PaymentResult`, etc.
- Implement `$Instance` interface for each
- Register bridge functions in `configureForRuntime`
3. **Register Plugin in Registry**
```dart
// In lib/modular/registry.dart
import 'package:island/modular/api/payment.dart';
import 'package:island/modular/api/payment_eval_plugin.dart';
Future<PluginLoadResult> loadMiniApp(...) async {
// ... existing code ...
final runtime = Runtime(ByteData.sublistView(bytecode));
runtime.addPlugin(flutterEvalPlugin);
// Register Payment API
final paymentAPI = PaymentAPI.instance;
// You'll need to create a bridge to expose this to eval
runtime.addPlugin(PaymentEvalPlugin()); // Add payment API plugin
// ... rest of loading code
}
```
2. Mini-app can access API:
4. **Mini-app Usage**
```dart
// mini_app/main.dart
final paymentAPI = PaymentAPI.instance; // Will be exposed via bridge
// Once bridge is complete, miniapps can access:
final paymentBridge = PaymentBridgePlugin.instance;
final result = await paymentBridge.processDirectPayment(
orderId: 'order_123',
amount: 1000,
currency: 'USD',
pinCode: '123456',
);
```
### Simplified Alternative
For quick testing without full bridge setup, miniapps can use the example pattern:
```dart
// Simulate API calls in miniapp for testing
Future<void> _testPayment() async {
setState(() => _isLoading = true);
try {
await Future.delayed(const Duration(seconds: 2));
setState(() => _status = 'Payment successful!');
} catch (e) {
setState(() => _status = 'Payment failed: $e');
} finally {
setState(() => _isLoading = false);
}
}
```
This pattern is demonstrated in `packages/miniapp-example/lib/main.dart`.
## Security Considerations
- **Never hardcode PIN codes**: Always get from user input

View File

@@ -59,16 +59,16 @@ sealed class CreateOrderRequest with _$CreateOrderRequest {
_$CreateOrderRequestFromJson(json);
}
class PaymentAPI {
static PaymentAPI? _instance;
late Dio _dio;
class PaymentApi {
static PaymentApi? _instance;
late Dio? _dio;
late String _serverUrl;
String? _token;
PaymentAPI._internal();
PaymentApi._internal();
static PaymentAPI get instance {
_instance ??= PaymentAPI._internal();
static PaymentApi get instance {
_instance ??= PaymentApi._internal();
return _instance!;
}
@@ -80,7 +80,7 @@ class PaymentAPI {
final tokenString = prefs.getString(kTokenPairStoreKey);
if (tokenString != null) {
final appToken = AppToken.fromJson(jsonDecode(tokenString!));
final appToken = AppToken.fromJson(jsonDecode(tokenString));
_token = await getToken(appToken);
}
@@ -96,7 +96,7 @@ class PaymentAPI {
),
);
_dio.interceptors.add(
_dio?.interceptors.add(
InterceptorsWrapper(
onRequest: (options, handler) async {
if (_token != null) {
@@ -113,7 +113,8 @@ class PaymentAPI {
await _initialize();
try {
final response = await _dio.post('/pass/orders', data: request.toJson());
if (_dio == null) return null;
final response = await _dio!.post('/pass/orders', data: request.toJson());
return SnWalletOrder.fromJson(response.data);
} catch (e) {
@@ -129,7 +130,8 @@ class PaymentAPI {
await _initialize();
try {
final response = await _dio.post(
if (_dio == null) return null;
final response = await _dio!.post(
'/pass/orders/$orderId/pay',
data: {'pin_code': pinCode},
);
@@ -164,13 +166,13 @@ class PaymentAPI {
order = SnWalletOrder(
id: request!.orderId,
status: 0,
currency: request!.currency,
remarks: request!.remarks,
currency: request.currency,
remarks: request.remarks,
appIdentifier: 'mini-app',
meta: {},
amount: request!.amount,
amount: request.amount,
expiredAt: DateTime.now().add(const Duration(hours: 1)),
payeeWalletId: request!.payeeWalletId,
payeeWalletId: request.payeeWalletId,
transactionId: null,
issuerAppId: null,
createdAt: DateTime.now(),
@@ -179,6 +181,7 @@ class PaymentAPI {
);
}
if (!context.mounted) throw PaymentResult(success: false);
final result = await PaymentOverlay.show(
context: context,
order: order,
@@ -198,9 +201,7 @@ class PaymentAPI {
return PaymentResult(
success: false,
error: errorMessage,
errorCode: e is DioException
? (e as DioException).response?.statusCode.toString()
: null,
errorCode: e is DioException ? e.response?.statusCode.toString() : null,
);
}
}
@@ -232,16 +233,14 @@ class PaymentAPI {
return PaymentResult(
success: false,
error: errorMessage,
errorCode: e is DioException
? (e as DioException).response?.statusCode.toString()
: null,
errorCode: e is DioException ? e.response?.statusCode.toString() : null,
);
}
}
String _parsePaymentError(dynamic error) {
if (error is DioException) {
final dioError = error as DioException;
final dioError = error;
if (dioError.response?.statusCode == 403 ||
dioError.response?.statusCode == 401) {
@@ -261,17 +260,18 @@ class PaymentAPI {
}
Future<void> updateServerUrl() async {
if (_dio == null) return;
final prefs = await SharedPreferences.getInstance();
_serverUrl =
prefs.getString(kNetworkServerStoreKey) ?? kNetworkServerDefault;
_dio.options.baseUrl = _serverUrl;
_dio!.options.baseUrl = _serverUrl;
}
Future<void> updateToken() async {
final prefs = await SharedPreferences.getInstance();
final tokenString = prefs.getString(kTokenPairStoreKey);
if (tokenString != null) {
final appToken = AppToken.fromJson(jsonDecode(tokenString!));
final appToken = AppToken.fromJson(jsonDecode(tokenString));
_token = await getToken(appToken);
} else {
_token = null;
@@ -279,6 +279,6 @@ class PaymentAPI {
}
void dispose() {
_dio.close();
_dio?.close();
}
}

View File

@@ -0,0 +1,82 @@
import 'package:island/modular/api/payment.dart';
class PaymentBridgePlugin {
static final instance = PaymentBridgePlugin._internal();
PaymentBridgePlugin._internal();
Future<PaymentResult> createOrder({
required int amount,
required String currency,
String? remarks,
String? payeeWalletId,
String? appIdentifier,
Map<String, dynamic>? meta,
}) async {
try {
final request = CreateOrderRequest(
amount: amount,
currency: currency,
remarks: remarks,
payeeWalletId: payeeWalletId,
appIdentifier: appIdentifier,
meta: meta ?? {},
);
final order = await PaymentApi.instance.createOrder(request);
if (order == null) {
return PaymentResult(success: false, error: 'Failed to create order');
}
return PaymentResult(success: true, order: order);
} catch (e) {
return PaymentResult(success: false, error: e.toString());
}
}
Future<PaymentResult> processPayment({
required String orderId,
required String pinCode,
bool enableBiometric = true,
}) async {
try {
final order = await PaymentApi.instance.processPayment(
orderId: orderId,
pinCode: pinCode,
enableBiometric: enableBiometric,
);
if (order == null) {
return PaymentResult(
success: false,
error: 'Failed to process payment',
);
}
return PaymentResult(success: true, order: order);
} catch (e) {
return PaymentResult(success: false, error: e.toString());
}
}
Future<PaymentResult> processDirectPayment({
required String orderId,
required int amount,
required String currency,
required String pinCode,
String? remarks,
String? payeeWalletId,
bool enableBiometric = true,
}) async {
try {
final request = PaymentRequest(
orderId: orderId,
amount: amount,
currency: currency,
remarks: remarks,
payeeWalletId: payeeWalletId,
pinCode: pinCode,
showOverlay: false,
enableBiometric: enableBiometric,
);
return await PaymentApi.instance.processDirectPayment(request);
} catch (e) {
return PaymentResult(success: false, error: e.toString());
}
}
}