currency_sdk 1.0.1
currency_sdk: ^1.0.1 copied to clipboard
Free, open-source currency conversion SDK for Flutter with 160+ currencies and offline-first architecture. No API keys required.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:currency_sdk/currency_sdk.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Currency SDK Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const CurrencyConverterExample(),
);
}
}
class CurrencyConverterExample extends StatefulWidget {
const CurrencyConverterExample({super.key});
@override
State<CurrencyConverterExample> createState() =>
_CurrencyConverterExampleState();
}
class _CurrencyConverterExampleState extends State<CurrencyConverterExample> {
final CurrencyClient _client = CurrencyClient();
final TextEditingController _amountController = TextEditingController();
String _fromCurrency = 'USD';
String _toCurrency = 'EUR';
double? _convertedAmount;
bool _isLoading = false;
bool _isInitialized = false;
bool _isOnline = false;
String? _error;
List<String> _currencies = [];
@override
void initState() {
super.initState();
_initializeSDK();
}
Future<void> _initializeSDK() async {
setState(() {
_isLoading = true;
_error = null;
});
try {
// Initialize SDK (free tier - no API key needed)
await _client.initialize();
// Listen to connectivity changes
_client.connectivityStream.listen((isOnline) {
setState(() {
_isOnline = isOnline;
});
});
// Get initial connectivity status
_isOnline = _client.isOnline;
// Load available currencies
final currencies = await _client.getSupportedCurrencies();
setState(() {
_isInitialized = true;
_currencies = currencies;
_isLoading = false;
});
} catch (e) {
setState(() {
_error = 'Failed to initialize: ${e.toString()}';
_isLoading = false;
});
}
}
Future<void> _convertCurrency() async {
if (_amountController.text.isEmpty) return;
setState(() {
_isLoading = true;
_error = null;
_convertedAmount = null;
});
try {
final amount = double.parse(_amountController.text);
// Use SDK to convert
final result = await _client.convert(
amount: amount,
from: _fromCurrency,
to: _toCurrency,
);
setState(() {
_convertedAmount = result;
_isLoading = false;
});
} on FormatException {
setState(() {
_error = 'Please enter a valid number';
_isLoading = false;
});
} on CurrencySDKException catch (e) {
setState(() {
_error = e.message;
_isLoading = false;
});
} catch (e) {
setState(() {
_error = e.toString();
_isLoading = false;
});
}
}
@override
void dispose() {
_client.dispose();
_amountController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
if (!_isInitialized) {
return Scaffold(
appBar: AppBar(title: const Text('Currency SDK Example')),
body: Center(
child: _error != null
? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.error_outline,
size: 64,
color: Colors.red,
),
const SizedBox(height: 16),
Text(_error!, textAlign: TextAlign.center),
const SizedBox(height: 16),
ElevatedButton(
onPressed: _initializeSDK,
child: const Text('Retry'),
),
],
)
: const CircularProgressIndicator(),
),
);
}
return Scaffold(
appBar: AppBar(
title: const Text('Currency SDK Example'),
actions: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
Icon(
_isOnline ? Icons.wifi : Icons.wifi_off,
color: _isOnline ? Colors.green : Colors.red,
),
const SizedBox(width: 4),
Text(_isOnline ? 'Online' : 'Offline'),
],
),
),
],
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Amount input
TextField(
controller: _amountController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
labelText: 'Amount',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.attach_money),
),
),
const SizedBox(height: 16),
// From currency dropdown
DropdownButtonFormField<String>(
value: _fromCurrency,
decoration: const InputDecoration(
labelText: 'From',
border: OutlineInputBorder(),
),
items: _currencies
.map(
(code) => DropdownMenuItem(value: code, child: Text(code)),
)
.toList(),
onChanged: (value) {
setState(() {
_fromCurrency = value!;
});
},
),
const SizedBox(height: 16),
// To currency dropdown
DropdownButtonFormField<String>(
value: _toCurrency,
decoration: const InputDecoration(
labelText: 'To',
border: OutlineInputBorder(),
),
items: _currencies
.map(
(code) => DropdownMenuItem(value: code, child: Text(code)),
)
.toList(),
onChanged: (value) {
setState(() {
_toCurrency = value!;
});
},
),
const SizedBox(height: 24),
// Convert button
ElevatedButton(
onPressed: _isLoading ? null : _convertCurrency,
child: _isLoading
? const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Text('Convert'),
),
const SizedBox(height: 24),
// Result
if (_convertedAmount != null)
Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
const Text(
'Result',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Text(
'${_amountController.text} $_fromCurrency = ${_convertedAmount!.toStringAsFixed(2)} $_toCurrency',
style: const TextStyle(fontSize: 20),
textAlign: TextAlign.center,
),
],
),
),
),
// Error
if (_error != null)
Card(
color: Colors.red.shade50,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
_error!,
style: const TextStyle(color: Colors.red),
textAlign: TextAlign.center,
),
),
),
const Spacer(),
// Info card
Card(
color: Colors.blue.shade50,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'SDK Features:',
style: TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
const Text('✅ 160+ currencies'),
const Text('✅ Offline-first caching'),
const Text('✅ Real-time updates every 2 hours'),
const Text('✅ Free tier - no API key needed'),
const SizedBox(height: 8),
Text(
'Status: ${_isOnline ? 'Using live data' : 'Using cached data'}',
style: TextStyle(
color: _isOnline ? Colors.green : Colors.orange,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
],
),
),
);
}
}