guardo 1.0.0
guardo: ^1.0.0 copied to clipboard
A Flutter package that provides secure app entry point with auto-locking, biometric authentication, and lifecycle management.
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:guardo/guardo.dart';
import 'guardo_localizations_ko.dart';
// Custom LocalizationsDelegate that includes Korean support for the example app
class ExampleGuardoLocalizationsDelegate
extends LocalizationsDelegate<GuardoLocalizations> {
const ExampleGuardoLocalizationsDelegate();
@override
Future<GuardoLocalizations> load(Locale locale) async {
if (locale.languageCode == 'ko') {
return GuardoLocalizationsKo();
} else {
// Fall back to the main Guardo localizations delegate for other languages
return await GuardoLocalizations.delegate.load(locale);
}
}
@override
bool isSupported(Locale locale) => <String>[
'en', 'es', 'ar', 'ko', // Korean added
].contains(locale.languageCode);
@override
bool shouldReload(ExampleGuardoLocalizationsDelegate old) => false;
}
void main() {
runApp(const ExampleApp());
}
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) {
return Guardo(
// Enable/disable authentication completely
// Set to false to bypass all authentication (useful for testing/debugging)
enabled: true,
// Configuration for the authentication
config: GuardoConfig(
localizedReason: 'Please authenticate to access the secure app',
// Use biometrics by default - lockout scenarios will automatically fallback to device credentials
biometricOnly: true,
stickyAuth: true,
// Lock the app after 30 seconds of inactivity
lockTimeout: const Duration(seconds: 40),
// Show lock screen instead of auto-checking authentication
autoCheckOnStart: false,
// Use biometric authentication by default
authenticationOptions: const AuthenticationOptions(
biometricOnly: true, // Normal biometric authentication
stickyAuth: true,
),
),
onAuthenticationChanged: (isAuthenticated) {
debugPrint('Authentication state changed: $isAuthenticated');
},
// 🔑 NEW: Pass localization configuration directly to Guardo
// This ensures all Guardo's internal screens (loading, error, lock screen) use proper localization
localizationsDelegates: const [
ExampleGuardoLocalizationsDelegate(),
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
locale: const Locale('en', ''),
supportedLocales: const [
Locale('ar', ''), // Arabic
Locale('en', ''), // English
Locale('es', ''), // Spanish
Locale('ko', ''), // Korean
],
child: MaterialApp(
title: 'Secure App',
theme: ThemeData(useMaterial3: true),
localizationsDelegates: const [
ExampleGuardoLocalizationsDelegate(),
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
locale: const Locale('ko', ''),
supportedLocales: const [
Locale('ar', ''), // Arabic
Locale('en', ''), // English
Locale('es', ''), // Spanish
Locale('ko', ''), // Korean
],
home: const SecureHomePage(),
),
);
}
}
class SecureHomePage extends StatefulWidget {
const SecureHomePage({super.key});
@override
State<SecureHomePage> createState() => _SecureHomePageState();
}
class _SecureHomePageState extends State<SecureHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Secure App'),
actions: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
context.guardo.isAuthenticated ? Icons.lock_open : Icons.lock,
color: context.guardo.isAuthenticated
? Colors.green
: Colors.red,
),
const SizedBox(width: 4),
Text(
context.guardo.isAuthenticated ? 'Unlocked' : 'Locked',
style: TextStyle(
color: context.guardo.isAuthenticated
? Colors.green
: Colors.red,
fontSize: 12,
),
),
],
),
),
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.security, size: 64, color: Colors.green),
const SizedBox(height: 16),
const Text(
'Welcome to the Secure App!',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
const Text(
'You have successfully authenticated',
style: TextStyle(fontSize: 16, color: Colors.grey),
),
const SizedBox(height: 32),
// Lock App Button
ElevatedButton.icon(
onPressed: () {
context.guardo.lockApp();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('App locked manually')),
);
},
icon: const Icon(Icons.lock),
label: const Text('Lock App'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.redAccent,
foregroundColor: Colors.white,
),
),
const SizedBox(height: 16),
// Unlock App Button
ElevatedButton.icon(
onPressed: () async {
final messenger = ScaffoldMessenger.of(context);
final unlocked = await context.guardo.unlockApp();
if (mounted) {
messenger.showSnackBar(
SnackBar(
content: Text(
unlocked
? 'App unlocked successfully'
: 'Failed to unlock app',
),
backgroundColor: unlocked ? Colors.green : Colors.red,
),
);
}
},
icon: const Icon(Icons.lock_open),
label: const Text('Unlock App'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.green,
foregroundColor: Colors.white,
),
),
const SizedBox(height: 16),
// Reset Lock Timer Button
ElevatedButton.icon(
onPressed: () {
context.guardo.resetLockTimer();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Lock timer reset')),
);
},
icon: const Icon(Icons.timer),
label: const Text('Reset Lock Timer'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
),
),
const SizedBox(height: 32),
// Unified action example (sync)
ElevatedButton.icon(
onPressed: () {
context.guardo.action(
onSuccess: () {
debugPrint('Sync Action Success');
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Sync action completed successfully'),
backgroundColor: Colors.green,
),
);
},
onFailure: (e) {
debugPrint('Sync Action Failed: $e');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Sync action failed: $e'),
backgroundColor: Colors.red,
),
);
},
reason: 'Please authenticate to perform this sync action',
);
},
icon: const Icon(Icons.verified_user),
label: const Text('Perform Sync Action'),
),
const SizedBox(height: 16),
// Unified action example (async)
ElevatedButton.icon(
onPressed: () {
context.guardo.action(
onSuccess: () async {
debugPrint('Async Action Success');
final messenger = ScaffoldMessenger.of(context);
// Simulate async work
await Future.delayed(const Duration(seconds: 1));
if (mounted) {
messenger.showSnackBar(
const SnackBar(
content: Text('Async action completed successfully'),
backgroundColor: Colors.blue,
),
);
}
},
onFailure: (e) async {
debugPrint('Async Action Failed: $e');
final messenger = ScaffoldMessenger.of(context);
if (mounted) {
messenger.showSnackBar(
SnackBar(
content: Text('Async action failed: $e'),
backgroundColor: Colors.red,
),
);
}
},
reason: 'Please authenticate to perform this async action',
);
},
icon: const Icon(Icons.cloud_upload),
label: const Text('Perform Async Action'),
),
const SizedBox(height: 16),
// Authentication status info
Card(
margin: const EdgeInsets.all(16),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
const Text(
'Authentication Status',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text('Is Authenticated:'),
Text(
context.guardo.isAuthenticated ? 'Yes' : 'No',
style: TextStyle(
color: context.guardo.isAuthenticated
? Colors.green
: Colors.red,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 8),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text('Is App Locked:'),
Text(
context.guardo.isAppLocked ? 'Yes' : 'No',
style: TextStyle(
color: context.guardo.isAppLocked
? Colors.red
: Colors.green,
fontWeight: FontWeight.bold,
),
),
],
),
],
),
),
),
],
),
),
);
}
}