saafe_aa_sdk 0.1.4
saafe_aa_sdk: ^0.1.4 copied to clipboard
Flutter SDK for integrating SAAFE's secure authentication and financial experience
example/lib/main.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'dart:io' show Platform;
import 'package:saafe_aa_sdk/saafe_sdk.dart';
import 'package:http/http.dart' as http;
void main() async {
// Initialize the SDK with default redirect URL
await SaafeSdk.initialize();
// Alternatively, use a custom redirect URL
// await SaafeSdk.initialize(customRedirectUrl: 'https://your-custom-redirect.example.com/login');
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Saafe SDK Example',
theme: ThemeData(
primarySwatch: Colors.blue,
useMaterial3: true,
),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
SaafeRedirectInstance? _redirectInstance;
String _resultMessage = '';
bool _isLoading = false;
// Hardcoded consent values from API response as fallback
final String _fiValue = 'WU9AUEBGV0dXUB5QWUc=';
final String _reqdateValue = '160520250536024';
final String _ecreqValue = 'PuH3d0DSVsNCH3tfu86D4iNKTOYZyyftje7GLsc84gwMcmjFifpO9Pf4v8gDZ0lN4pD7Koskq-CkrHFGRpkvh16HVVjCjmhHiQaKRGuRo1MjoxiqicJJcQP0k-MJwDYR6krtMHFr3RP_W4Trlj2aAxeoucAvoJhGI1Lm5fnsCnnU64BHl7vPHGyXovHZIXl4sr8_HLQPuBkgLUy5oeu0fDDY62ajnztF40KufzuNe5MLI0Aut2_OjR-S94rdFrkbM6IseaBsPbpZnnibU8GuKL3A9idlvBDbLRNvEtgnjKy6AKGMAWQtEC1l6waJKeedhl0j4qCpNLtNBOCXb3VS5sf5kafDitfuSgpJ0pfuA-8=';
// Dynamic consent values that will be fetched from API
String? _dynamicFi;
String? _dynamicReqdate;
String? _dynamicEcreq;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Saafe SDK Example'),
),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// API fetch button
ElevatedButton(
onPressed: _isLoading ? null : _fetchConsentData,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.teal,
foregroundColor: Colors.white,
),
child: _isLoading
? const Row(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
color: Colors.white,
),
),
SizedBox(width: 10),
Text('Fetching...'),
],
)
: const Text('Fetch Latest Consent Data'),
),
const SizedBox(height: 16),
// Show which consent data is being used
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: Text(
_hasDynamicData
? 'Using data from API'
: 'Using fallback hardcoded data',
style: TextStyle(
fontWeight: FontWeight.bold,
color: _hasDynamicData ? Colors.green : Colors.orange,
),
),
),
const SizedBox(height: 30),
// Theme selection
const Text(
'Theme Selection:',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
const SizedBox(height: 8),
Wrap(
spacing: 10,
children: [
_buildThemeButton('Light Theme', 'light'),
_buildThemeButton('Dark Theme', 'dark'),
_buildThemeButton('System Theme', null),
],
),
const SizedBox(height: 30),
// Result display
if (_resultMessage.isNotEmpty)
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(8),
),
child: Text(_resultMessage),
),
const Spacer(),
// Close button for active sessions
if (_redirectInstance != null)
ElevatedButton(
onPressed: () {
// This will show the confirmation dialog before closing
_redirectInstance?.close();
setState(() {
_redirectInstance = null;
});
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red,
foregroundColor: Colors.white,
),
child: const Text('Close Redirect Session'),
),
],
),
),
);
}
// Check if we have dynamic data from API
bool get _hasDynamicData =>
_dynamicFi != null && _dynamicReqdate != null && _dynamicEcreq != null;
// Get active fi value (dynamic or fallback)
String get _activeFi => _dynamicFi ?? _fiValue;
// Get active reqdate value (dynamic or fallback)
String get _activeReqdate => _dynamicReqdate ?? _reqdateValue;
// Get active ecreq value (dynamic or fallback)
String get _activeEcreq => _dynamicEcreq ?? _ecreqValue;
// Fetch consent data from API
Future<void> _fetchConsentData() async {
setState(() {
_isLoading = true;
_resultMessage = 'Fetching consent data...';
});
try {
// This is a mock function - replace with your actual API call
// In a real app, you would call your backend to generate a consent URL
final response = await _mockGenerateConsent();
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
setState(() {
_dynamicFi = data['fi'];
_dynamicReqdate = data['reqdate'];
_dynamicEcreq = data['ecreq'];
_resultMessage = 'Consent data fetched successfully!';
});
} else {
setState(() {
_resultMessage = 'Failed to fetch consent data: ${response.statusCode}';
});
}
} catch (e) {
setState(() {
_resultMessage = 'Error fetching consent data: $e\nUsing fallback data.';
});
} finally {
setState(() {
_isLoading = false;
});
}
}
// Mock function to simulate API call
// In a real app, you would call your actual API
Future<http.Response> _mockGenerateConsent() async {
// Simulate network delay
await Future.delayed(const Duration(seconds: 2));
// Return a mock response with the same data as our hardcoded values
// In a real app, this would be a real API call
final mockJsonResponse = {
"status": "success",
"code": "OperationSuccess",
"msg": "Operation Success",
"request_id": 7788,
"txn_id": "daa53abbc1-7fe7-4984-8879-197883daba9d",
"url": "https://sandbox.redirection.saafe.in/login/?fi=WU9AUEBGV0dXUB5QWUc=&reqdate=160520250536024&ecreq=PuH3d0DSVsNCH3tfu86D4iNKTOYZyyftje7GLsc84gwMcmjFifpO9Pf4v8gDZ0lN4pD7Koskq-CkrHFGRpkvh16HVVjCjmhHiQaKRGuRo1MjoxiqicJJcQP0k-MJwDYR6krtMHFr3RP_W4Trlj2aAxeoucAvoJhGI1Lm5fnsCnnU64BHl7vPHGyXovHZIXl4sr8_HLQPuBkgLUy5oeu0fDDY62ajnztF40KufzuNe5MLI0Aut2_OjR-S94rdFrkbM6IseaBsPbpZnnibU8GuKL3A9idlvBDbLRNvEtgnjKy6AKGMAWQtEC1l6waJKeedhl0j4qCpNLtNBOCXb3VS5sf5kafDitfuSgpJ0pfuA-8=",
"consent_handle": [
"8bce1c3b-f289-4c1c-8d4b-7ed2e0d3a31b",
"b6bc69f8-c77d-4070-a9ec-0d4ad7c72be2"
],
"vua": "8682807087@dashboard-aa-preprod",
"fi": "WU9AUEBGV0dXUB5QWUc=",
"reqdate": "160520250536024",
"ecreq": "PuH3d0DSVsNCH3tfu86D4iNKTOYZyyftje7GLsc84gwMcmjFifpO9Pf4v8gDZ0lN4pD7Koskq-CkrHFGRpkvh16HVVjCjmhHiQaKRGuRo1MjoxiqicJJcQP0k-MJwDYR6krtMHFr3RP_W4Trlj2aAxeoucAvoJhGI1Lm5fnsCnnU64BHl7vPHGyXovHZIXl4sr8_HLQPuBkgLUy5oeu0fDDY62ajnztF40KufzuNe5MLI0Aut2_OjR-S94rdFrkbM6IseaBsPbpZnnibU8GuKL3A9idlvBDbLRNvEtgnjKy6AKGMAWQtEC1l6waJKeedhl0j4qCpNLtNBOCXb3VS5sf5kafDitfuSgpJ0pfuA-8="
};
return http.Response(
jsonEncode(mockJsonResponse),
200,
headers: {'content-type': 'application/json'},
);
}
Widget _buildThemeButton(String label, String? theme) {
return ElevatedButton(
onPressed: () => _openRedirectWithTheme(theme),
child: Text(label),
);
}
Future<void> _openRedirectWithTheme(String? theme) async {
setState(() {
_resultMessage = 'Opening redirect with theme: ${theme ?? 'system'}';
});
try {
_redirectInstance = await SaafeSdk.triggerRedirect(
context,
SaafeRedirectOptions(
fi: _activeFi,
reqdate: _activeReqdate,
ecreq: _activeEcreq,
theme: theme,
onComplete: (data) {
setState(() {
_resultMessage = 'Completed: $data';
_redirectInstance = null;
});
},
onCancel: () {
setState(() {
_resultMessage = 'Cancelled by user';
_redirectInstance = null;
});
},
onError: (error) {
setState(() {
_resultMessage = 'Error: $error';
_redirectInstance = null;
});
},
onLoad: () {
setState(() {
_resultMessage = 'WebView loaded successfully';
});
},
),
);
} catch (e) {
setState(() {
_resultMessage = 'Error triggering redirect: $e';
});
}
}
}