vove_id_flutter 1.6.0
vove_id_flutter: ^1.6.0 copied to clipboard
VOVE ID - Instant, seamless identity verification. Designed for trust, user-centric, fully compliant with AML/KYC. Optimized for the MEA region.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:vove_id_flutter/vove_id_flutter.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
Vove.initialize(
environment: VoveEnvironment.sandbox,
publicKey:
'6fc3fb00391916cfcd0e47d3a11a243054413ffcf220f9b3adb8d3c6db307842',
);
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final TextEditingController _sessionTokenController = TextEditingController(
text:
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2b3ZlSWQiOiI2OTJlYjlkMTgxMWRmZjgyYWYyMWZiMmUiLCJyZWZJZCI6ImJmMzZmNGYwLTc0MDgtNDUyZi1hMDk2LTQwNmNmMzg5MmY0MiIsIm9yZ0lkIjoiNjU4ZjAyZTQ4NmRkMWIzMmUzYjQwOTlmIiwic2Vzc2lvbklkIjoiNTU3NWNiZmQtMzEyNi00ZjE3LWI2MWYtYzNlOTRhM2QzMDBlIiwiaWF0IjoxNzY0NjY5OTA1LCJleHAiOjE3NjQ2NzE3MDV9.6dv03DfxpegZK28PqGIYkLFM94IG-WPFHR7g1xUTdpQ',
);
bool _isProcessing = false;
bool _showUI = true;
bool _exitAfterEachStep = false;
bool _enableVocalGuidance = false;
VoveLocale _selectedLocale = VoveLocale.en;
String _statusText = 'Idle';
String _nextStepText = 'N/A';
bool _maxAttemptsTriggered = false;
final List<String> _logLines = <String>[];
void _log(String message) {
setState(() {
_logLines.insert(0, '${DateTime.now().toIso8601String()} - $message');
});
}
Future<void> _startVerification() async {
final sessionToken = _sessionTokenController.text.trim();
if (sessionToken.isEmpty) {
_log('Please provide a valid session token.');
return;
}
setState(() {
_isProcessing = true;
_statusText = 'Processing...';
_nextStepText = 'N/A';
_maxAttemptsTriggered = false;
});
try {
final configuration = VoveStartConfiguration(
showUI: _showUI,
exitAfterEachStep: _exitAfterEachStep,
onMaxAttemptsReached: () {
_log('Max attempts callback triggered from Flutter.');
setState(() {
_maxAttemptsTriggered = true;
_isProcessing = false;
});
},
);
final result = await Vove.start(
sessionToken: sessionToken,
configuration: configuration,
locale: _selectedLocale,
enableVocalGuidance: _enableVocalGuidance,
);
setState(() {
_statusText = result.status.name;
_nextStepText = result.nextStep?.name ?? 'N/A';
});
_log(
'Verification completed. Status: ${result.status.name}'
'${result.nextStep != null ? ', Next step: ${result.nextStep!.name}' : ''}',
);
} on PlatformException catch (e) {
_log('Platform exception: ${e.message}');
setState(() {
_statusText = 'Error';
});
} catch (e) {
_log('Unexpected error: $e');
setState(() {
_statusText = 'Error';
});
} finally {
setState(() {
_isProcessing = false;
});
}
}
@override
void dispose() {
_sessionTokenController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Vove ID Flutter Example'),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
TextField(
controller: _sessionTokenController,
maxLines: 4,
decoration: const InputDecoration(
labelText: 'Session Token',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 16),
DropdownButtonFormField<VoveLocale>(
value: _selectedLocale,
decoration: const InputDecoration(
labelText: 'Locale',
border: OutlineInputBorder(),
),
items: VoveLocale.values
.map(
(locale) => DropdownMenuItem(
value: locale,
child: Text(locale.name.toUpperCase()),
),
)
.toList(),
onChanged: (locale) {
if (locale != null) {
setState(() => _selectedLocale = locale);
}
},
),
const SizedBox(height: 16),
SwitchListTile(
value: _showUI,
title: const Text('Show built-in UI'),
onChanged: (value) => setState(() => _showUI = value),
),
SwitchListTile(
value: _exitAfterEachStep,
title: const Text('Exit after each step'),
onChanged: (value) =>
setState(() => _exitAfterEachStep = value),
),
SwitchListTile(
value: _enableVocalGuidance,
title: const Text('Enable vocal guidance'),
onChanged: (value) =>
setState(() => _enableVocalGuidance = value),
),
const SizedBox(height: 16),
ElevatedButton.icon(
onPressed: _isProcessing ? null : _startVerification,
icon: _isProcessing
? const SizedBox(
height: 16,
width: 16,
child: CircularProgressIndicator(strokeWidth: 2),
)
: const Icon(Icons.verified),
label: const Text('Start Verification'),
),
const SizedBox(height: 24),
_StatusCard(
status: _statusText,
nextStep: _nextStepText,
maxAttemptsTriggered: _maxAttemptsTriggered,
),
const SizedBox(height: 16),
Text(
'Logs',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 8),
Container(
height: 200,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade300),
borderRadius: BorderRadius.circular(8),
),
child: _logLines.isEmpty
? const Center(child: Text('No logs yet'))
: ListView.builder(
reverse: true,
itemCount: _logLines.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.symmetric(
vertical: 4,
horizontal: 8,
),
child: Text(_logLines[index]),
);
},
),
),
],
),
),
),
);
}
}
class _StatusCard extends StatelessWidget {
const _StatusCard({
required this.status,
required this.nextStep,
required this.maxAttemptsTriggered,
});
final String status;
final String nextStep;
final bool maxAttemptsTriggered;
@override
Widget build(BuildContext context) {
return Card(
elevation: 2,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Current Status: $status',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 8),
Text('Next Step: $nextStep'),
const SizedBox(height: 8),
Row(
children: [
const Text('Max Attempts Callback: '),
Icon(
maxAttemptsTriggered ? Icons.check_circle : Icons.cancel,
color: maxAttemptsTriggered ? Colors.green : Colors.red,
),
],
),
],
),
),
);
}
}