avy_debug_panel 1.1.1
avy_debug_panel: ^1.1.1 copied to clipboard
A powerful in-app developer debug console for Flutter apps. Features gesture triggers, logs viewer, network inspector, device info, storage viewer, and feature toggles.
avy_debug_panel #
A powerful, customizable in-app developer debug console for Flutter apps. Features gesture triggers, logs viewer, network inspector, device info, storage viewer, feature toggles, and theme customization.
Features #
- ๐ง Debug Overlay - Full-screen modal panel that appears above your app UI
- ๐ Gesture Triggers - Long press, three-finger tap, or device shake to open
- ๐ Logs Viewer - Timestamped, searchable logs with level filtering and tags
- ๐ Network Inspector - Dio interceptor for HTTP request/response logging
- ๐ Environment Switcher - Switch between dev, staging, and production environments at runtime
- ๐ State Inspector - Monitor Provider, Riverpod, BLoC, and GetX state changes
- ๐ฑ Device Info Panel - Display device model, OS version, app version, build number
- ๐พ Storage Viewer - View all SharedPreferences keys and values
- ๐๏ธ Feature Toggles - Runtime feature flag management with categories
- ๐จ Theme Customization - Multiple built-in themes or create your own
- ๐ Copy/Export - Copy logs and data to clipboard or export as JSON
- ๐ Dark/Light Themes - Clean developer-style UI with multiple color schemes
- ๐ Tabbed Interface - Organized tabs for Logs, Network, Env, State, Device, Storage, Features
- ๐งช Fully Tested - Comprehensive unit and widget tests
Screenshots #
| Logs Panel | Network Panel | Device Info |
|---|---|---|
Installation #
Add this to your package's pubspec.yaml file:
dependencies:
avy_debug_panel: ^1.0.0
Or install via command line:
flutter pub add avy_debug_panel
Quick Start #
1. Initialize and Wrap Your App #
import 'package:avy_debug_panel/flutter_debug_panel.dart';
void main() {
// Initialize the debug panel
FlutterDebugPanel.init(
enable: true,
enableShake: true,
enableLongPress: true,
enableThreeFingerTap: true,
);
runApp(
FlutterDebugPanel.wrap(
MyApp(),
),
);
}
2. Log Messages #
import 'package:avy_debug_panel/flutter_debug_panel.dart';
// Basic logging
DebugLogger.log("User logged in");
// With log level
DebugLogger.log("API error", level: LogLevel.error);
// With tag
DebugLogger.log("Network request", tag: "Network");
// Convenience methods
DebugLogger.debug("Debug message");
DebugLogger.info("Info message");
DebugLogger.warning("Warning message");
DebugLogger.error("Error message");
3. Network Inspector (Dio) #
import 'package:dio/dio.dart';
import 'package:avy_debug_panel/flutter_debug_panel.dart';
final dio = Dio();
dio.interceptors.add(DebugNetworkInterceptor());
// All requests will now be logged
final response = await dio.get('https://api.example.com/data');
4. Environment Switcher #
import 'package:avy_debug_panel/flutter_debug_panel.dart';
// Register environments
DebugEnvironmentManager.registerAll([
Environment(
id: 'dev',
name: 'Development',
baseUrl: 'https://dev-api.example.com',
socketUrl: 'wss://dev-ws.example.com',
description: 'Development environment',
config: {'timeout': 30000, 'debug': true},
),
Environment(
id: 'staging',
name: 'Staging',
baseUrl: 'https://staging-api.example.com',
description: 'Staging environment',
),
Environment(
id: 'prod',
name: 'Production',
baseUrl: 'https://api.example.com',
description: 'Production environment',
),
]);
// Get current environment
final currentEnv = DebugEnvironmentManager.currentEnvironment;
final baseUrl = DebugEnvironmentManager.currentBaseUrl;
// Switch environment
DebugEnvironmentManager.setEnvironment('staging');
// Check environment type
if (DebugEnvironmentManager.isProduction) {
// Production-specific logic
}
// Listen to environment changes
DebugEnvironmentManager.addListener((environment) {
print('Switched to: ${environment?.name}');
// Update your API client with new baseUrl
});
5. State Inspector #
import 'package:avy_debug_panel/flutter_debug_panel.dart';
// Register state providers for monitoring
DebugStateInspector.registerProvider(
id: 'user_provider',
name: 'User Provider',
stateType: StateManagementType.provider,
initialValue: 'null',
);
DebugStateInspector.registerProvider(
id: 'cart_provider',
name: 'Cart Provider',
stateType: StateManagementType.riverpod,
initialValue: 'Cart(items: 0)',
);
// Log state changes
DebugStateInspector.logChange(
providerId: 'user_provider',
previousValue: 'null',
newValue: 'User(id: 123, name: "John")',
description: 'User logged in',
);
// Get change history
final changes = DebugStateInspector.changes;
final userChanges = DebugStateInspector.getChangesForProvider('user_provider');
// Export for debugging
final json = DebugStateInspector.exportJson();
Flutter Riverpod Integration
For flutter_riverpod, you can monitor state changes using the RiverpodInspector helper or by listening to provider changes:
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:avy_debug_panel/flutter_debug_panel.dart';
// Define your providers
final counterProvider = StateProvider<int>((ref) => 0);
final userProvider = StateNotifierProvider<UserNotifier, User?>((ref) {
return UserNotifier();
});
class UserNotifier extends StateNotifier<User?> {
UserNotifier() : super(null);
void login(User user) => state = user;
void logout() => state = null;
}
class User {
final int id;
final String name;
User({required this.id, required this.name});
@override
String toString() => 'User(id: $id, name: "$name")';
}
// Initialize and register providers for inspection
void initStateInspector() {
// Register Riverpod providers for monitoring
RiverpodInspector.register<int>(
providerName: 'counterProvider',
value: 0,
);
RiverpodInspector.register<User?>(
providerName: 'userProvider',
value: null,
);
}
// Widget that monitors provider changes
class MonitoredConsumer extends ConsumerWidget {
const MonitoredConsumer({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
// Listen to counter changes and log to inspector
ref.listen<int>(counterProvider, (previous, next) {
RiverpodInspector.logChange<int>(
providerName: 'counterProvider',
newValue: next,
previousValue: previous,
);
});
// Listen to user changes
ref.listen<User?>(userProvider, (previous, next) {
RiverpodInspector.logChange<User?>(
providerName: 'userProvider',
newValue: next,
previousValue: previous,
description: next != null ? 'User logged in' : 'User logged out',
);
});
final counter = ref.watch(counterProvider);
final user = ref.watch(userProvider);
return Column(
children: [
Text('Counter: $counter'),
Text('User: ${user?.name ?? "Not logged in"}'),
ElevatedButton(
onPressed: () => ref.read(counterProvider.notifier).state++,
child: const Text('Increment'),
),
ElevatedButton(
onPressed: () => ref.read(userProvider.notifier).login(
User(id: 1, name: 'John Doe'),
),
child: const Text('Login'),
),
],
);
}
}
// Alternative: Create a reusable inspection wrapper
class InspectableProviderListener<T> extends ConsumerWidget {
final ProviderListenable<T> provider;
final String providerName;
final Widget Function(T value) builder;
final String Function(T value)? valueToString;
const InspectableProviderListener({
super.key,
required this.provider,
required this.providerName,
required this.builder,
this.valueToString,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
ref.listen<T>(provider, (previous, next) {
DebugStateInspector.logChange(
providerId: providerName,
newValue: valueToString?.call(next) ?? next.toString(),
previousValue: previous != null
? (valueToString?.call(previous) ?? previous.toString())
: null,
);
});
return builder(ref.watch(provider));
}
}
// Usage of the wrapper
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return InspectableProviderListener<int>(
provider: counterProvider,
providerName: 'counterProvider',
builder: (value) => Text('Count: $value'),
);
}
}
Complete Riverpod Example with ProviderScope
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:avy_debug_panel/flutter_debug_panel.dart';
void main() {
// Initialize debug panel
FlutterDebugPanel.init(enable: true);
// Register providers for state inspection
RiverpodInspector.register(providerName: 'counter', value: 0);
RiverpodInspector.register(providerName: 'theme', value: 'light');
runApp(
FlutterDebugPanel.wrap(
ProviderScope(
child: MyApp(),
),
),
);
}
// Providers
final counterProvider = StateProvider<int>((ref) => 0);
final themeModeProvider = StateProvider<String>((ref) => 'light');
// App
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(home: HomeScreen());
}
}
class HomeScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
// Monitor state changes
ref.listen<int>(counterProvider, (prev, next) {
RiverpodInspector.logChange(
providerName: 'counter',
newValue: next,
previousValue: prev,
);
});
ref.listen<String>(themeModeProvider, (prev, next) {
RiverpodInspector.logChange(
providerName: 'theme',
newValue: next,
previousValue: prev,
);
});
final count = ref.watch(counterProvider);
return Scaffold(
body: Center(
child: Text('Count: $count'),
),
floatingActionButton: FloatingActionButton(
onPressed: () => ref.read(counterProvider.notifier).state++,
child: Icon(Icons.add),
),
);
}
}
6. Feature Flags #
import 'package:avy_debug_panel/flutter_debug_panel.dart';
// Register feature flags
DebugFeatureFlags.register(
'new_checkout',
'New Checkout Flow',
description: 'Enable the redesigned checkout experience',
category: 'Commerce',
defaultValue: false,
);
// Check if enabled
if (DebugFeatureFlags.isEnabled('new_checkout')) {
// Show new checkout
}
// Toggle at runtime
DebugFeatureFlags.enable('new_checkout');
DebugFeatureFlags.disable('new_checkout');
Configuration #
Basic Configuration #
FlutterDebugPanel.init(
// Enable/disable the entire panel
enable: true,
// Enable individual gesture triggers
enableShake: true,
enableLongPress: true,
enableThreeFingerTap: true,
// Long press duration before panel opens
longPressDuration: Duration(seconds: 2),
// Custom colors
backgroundColor: Color(0xFF1E1E1E),
accentColor: Colors.cyanAccent,
);
Advanced Configuration with Theme #
FlutterDebugPanel.initWithConfig(
DebugPanelConfig(
enable: true,
enableShake: true,
enableLongPress: true,
enableThreeFingerTap: true,
// Use predefined color scheme
colorScheme: DebugPanelColorScheme.darkPurple,
// Or provide a completely custom theme
theme: DebugPanelTheme(
backgroundColor: Color(0xFF121212),
surfaceColor: Color(0xFF1E1E1E),
accentColor: Colors.purple,
textPrimary: Colors.white,
textSecondary: Colors.grey,
successColor: Colors.green,
warningColor: Colors.orange,
errorColor: Colors.red,
infoColor: Colors.blue,
borderColor: Color(0xFF333333),
),
),
);
Theming #
Built-in Color Schemes #
// Dark theme with cyan accent (default)
DebugPanelColorScheme.darkCyan
// Dark theme with purple accent
DebugPanelColorScheme.darkPurple
// Dark theme with green accent
DebugPanelColorScheme.darkGreen
// Dark theme with orange accent
DebugPanelColorScheme.darkOrange
// Light theme with blue accent
DebugPanelColorScheme.lightBlue
Custom Theme #
Create your own theme by extending DebugPanelTheme:
const myTheme = DebugPanelTheme(
backgroundColor: Color(0xFF1A1A2E),
surfaceColor: Color(0xFF16213E),
accentColor: Color(0xFFE94560),
textPrimary: Colors.white,
textSecondary: Color(0xFFA0A0A0),
successColor: Color(0xFF4CAF50),
warningColor: Color(0xFFFF9800),
errorColor: Color(0xFFF44336),
infoColor: Color(0xFF2196F3),
borderColor: Color(0xFF2A2A4A),
borderRadius: 12.0,
defaultPadding: 16.0,
monoFontFamily: 'monospace',
);
Panels Overview #
Logs Panel #
- Displays timestamped log messages
- Filter by log level (debug, info, warning, error)
- Search functionality
- Copy logs to clipboard
- Tap to view details
- Auto-scroll to latest logs
- Export as JSON
Network Panel #
- HTTP request/response logging
- View request URL, headers, body
- View response status code, headers, body
- Response time tracking
- Filter by status (success/failed)
- Search by URL
- Color-coded HTTP methods (GET, POST, PUT, DELETE, etc.)
- Formatted JSON body display
Device Panel #
- App information (name, version, build number)
- Device information (model, manufacturer, OS)
- System information (platform, Dart version)
- Copy any value to clipboard
- Platform-specific details (Android, iOS, Web, etc.)
Storage Panel #
- View all SharedPreferences keys/values
- Search functionality
- Delete individual keys
- Clear all storage
- Copy values to clipboard
- Type indicators (String, Int, Double, Bool, List)
Features Panel #
- View all registered feature flags
- Toggle flags on/off
- Enable/disable all flags
- Reset to defaults
- Grouped by category
- Search functionality
API Reference #
FlutterDebugPanel #
| Method | Description |
|---|---|
init(...) |
Initialize with named parameters |
initWithConfig(config) |
Initialize with config object |
wrap(app) |
Wrap your app widget |
log(message, level, tag) |
Log a message |
clearLogs() |
Clear all logs |
clearNetworkLogs() |
Clear all network logs |
enableFeature(key) |
Enable a feature flag |
disableFeature(key) |
Disable a feature flag |
isFeatureEnabled(key) |
Check if flag is enabled |
config |
Get current configuration |
isEnabled |
Check if panel is enabled |
DebugLogger #
| Method | Description |
|---|---|
log(message, level, tag) |
Log with level and optional tag |
debug(message, tag) |
Log debug message |
info(message, tag) |
Log info message |
warning(message, tag) |
Log warning message |
error(message, tag) |
Log error message |
clear() |
Clear all logs |
export() |
Export logs as string |
exportJson() |
Export logs as JSON |
search(query) |
Search logs |
getLogsByLevel(level) |
Get logs by level |
getLogsByTag(tag) |
Get logs by tag |
addListener(listener) |
Add log listener |
removeListener(listener) |
Remove log listener |
DebugNetworkLogger #
| Method | Description |
|---|---|
logRequest(request) |
Log a network request |
updateRequest(request) |
Update an existing request |
clear() |
Clear all requests |
search(query) |
Search by URL |
getByStatus(success) |
Filter by status |
addListener(listener) |
Add request listener |
removeListener(listener) |
Remove request listener |
DebugFeatureFlags #
| Method | Description |
|---|---|
register(key, name, ...) |
Register a new flag |
registerAll(flags) |
Register multiple flags |
enable(key) |
Enable a flag |
disable(key) |
Disable a flag |
toggle(key) |
Toggle a flag |
set(key, value) |
Set flag to specific value |
isEnabled(key) |
Check if enabled |
getFlag(key) |
Get flag by key |
exists(key) |
Check if flag exists |
unregister(key) |
Remove a flag |
clear() |
Remove all flags |
enableAll() |
Enable all flags |
disableAll() |
Disable all flags |
resetAll() |
Reset all to defaults |
export() |
Export flags as map |
import(values) |
Import flags from map |
allFlags |
Get all flags |
flagsByCategory |
Get flags grouped by category |
categories |
Get all categories |
addListener(listener) |
Add flag change listener |
removeListener(listener) |
Remove listener |
LogEntry #
| Property | Description |
|---|---|
timestamp |
When the log was created |
message |
The log message |
level |
Log level (debug, info, warning, error) |
tag |
Optional category tag |
formattedTimestamp |
Formatted time string |
toMap() |
Convert to map |
toJson() |
Convert to JSON |
DebugNetworkRequest #
| Property | Description |
|---|---|
id |
Unique identifier |
url |
Request URL |
method |
HTTP method |
headers |
Request headers |
body |
Request body |
statusCode |
Response status code |
responseBody |
Response body |
durationMs |
Response time in ms |
isSuccess |
Whether request succeeded |
isError |
Whether request failed |
shortUrl |
URL path without domain |
queryParams |
Query parameters |
Best Practices #
Only Enable in Debug Mode #
FlutterDebugPanel.init(
enable: kDebugMode, // Only in debug builds
enableShake: kDebugMode,
enableLongPress: kDebugMode,
);
Use Tags for Categorization #
DebugLogger.log("User action", tag: "Analytics");
DebugLogger.log("API response", tag: "Network");
DebugLogger.log("Database query", tag: "Database");
Use Log Levels Appropriately #
DebugLogger.debug("Verbose debug info"); // Detailed debugging
DebugLogger.info("User logged in"); // Important events
DebugLogger.warning("Slow network"); // Potential issues
DebugLogger.error("API failed"); // Errors
Organize Feature Flags with Categories #
DebugFeatureFlags.register('dark_mode', 'Dark Mode', category: 'UI');
DebugFeatureFlags.register('analytics', 'Analytics', category: 'Tracking');
DebugFeatureFlags.register('new_api', 'New API', category: 'Backend');
Architecture #
The package follows a clean architecture with:
- Core Services:
DebugLogger,DebugNetworkLogger,DebugFeatureFlags - Configuration:
DebugPanelConfig,DebugPanelTheme - UI Layer: Panels, overlay, and common widgets
- Theme System: Customizable theming with color schemes
lib/
โโโ flutter_debug_panel.dart # Main entry point
โโโ logger.dart # Logger implementation
โโโ network_logger.dart # Network logger + Dio interceptor
โโโ feature_flags.dart # Feature flags manager
โโโ debug_overlay.dart # Overlay widget
โโโ debug_panel.dart # Main panel widget
โโโ panels/
โ โโโ logs_panel.dart
โ โโโ network_panel.dart
โ โโโ device_panel.dart
โ โโโ storage_panel.dart
โ โโโ feature_flags_panel.dart
โโโ src/
โโโ theme/
โ โโโ debug_panel_theme.dart
โโโ widgets/
โ โโโ common_widgets.dart
โโโ services/
โโโ logger_service.dart
Testing #
The package includes comprehensive tests. Run them with:
flutter test
Test coverage includes:
- Unit tests for all core services
- Widget tests for panels and UI components
- Integration tests for the debug panel workflow
Dependencies #
dio- HTTP client for network interceptordevice_info_plus- Device informationshared_preferences- Storage viewershake- Shake gesture detectionintl- Date formatting
Platform Support #
| Platform | Support |
|---|---|
| Android | โ |
| iOS | โ |
| Web | โ |
| macOS | โ |
| Windows | โ |
| Linux | โ |
Changelog #
See CHANGELOG.md for a list of changes.
License #
MIT License - see LICENSE file.
Contributing #
Contributions are welcome! Please read the contributing guidelines before submitting a PR.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Development Setup #
# Clone the repo
git clone https://github.com/Avinashrola/avy_debug_panel.git
# Install dependencies
flutter pub get
# Run tests
flutter test
# Run the example app
cd example && flutter run
Issues #
Please file issues on the GitHub issue tracker.
Author #
Created by Avinash Rola
Sponsor #
If you find this package useful, consider sponsoring its development.