easy_debug 0.0.4 copy "easy_debug: ^0.0.4" to clipboard
easy_debug: ^0.0.4 copied to clipboard

A pure Dart in-app network debugger for Flutter. visualize Dio requests with a floating overlay, detailed inspection, and log management.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:easy_debug/easy_debug.dart';
import 'package:dio/dio.dart';
import 'package:http/http.dart' as http;

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Config Easy Debug
  EasyDebugManager().updateConfig(
    const EasyDebugConfig(clearOnNavigation: false, maxLogCount: 50),
  );

  // Initialize Environments
  await EasyDebugManager().init(
    environments: [
      const AppEnvironment(
        name: 'Production',
        baseUrl: 'https://jsonplaceholder.typicode.com',
        isDefault: true,
      ),
      const AppEnvironment(
        name: 'Development',
        baseUrl: 'https://dev.jsonplaceholder.typicode.com',
      ),
    ],
  );

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Easy Debug Example',
      theme: ThemeData(primarySwatch: Colors.blue),
      navigatorObservers: [EasyDebugNavigatorObserver()],
      builder: (context, child) {
        return EasyDebugWidget(child: child!);
      },
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final Dio _dio = Dio();
  late EasyDebugHttpClient _httpClient;

  @override
  void initState() {
    super.initState();
    _dio.interceptors.add(EasyDebugDioInterceptor());
    _httpClient = EasyDebugHttpClient(http.Client());

    // 1. Set initial BaseUrl
    _dio.options.baseUrl = EasyDebugManager().currentBaseUrl;

    // 2. Listen for environment changes
    EasyDebugManager().currentEnvNotifier.addListener(_onEnvChanged);
  }

  @override
  void dispose() {
    // 3. Remove listener to prevent memory leaks
    EasyDebugManager().currentEnvNotifier.removeListener(_onEnvChanged);
    _httpClient.close();
    super.dispose();
  }

  void _onEnvChanged() {
    final newEnv = EasyDebugManager().currentEnvNotifier.value;
    if (newEnv != null) {
      setState(() {
        _dio.options.baseUrl = newEnv.baseUrl;
      });
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Switched to ${newEnv.name} Environment')),
      );
    }
  }

  Future<void> _makeRequest(String path, String method) async {
    // Now we just use the relative path, Dio handles the BaseUrl
    try {
      if (method == 'GET') {
        await _dio.get(path);
      } else if (method == 'POST') {
        await _dio.post(
          path,
          data: {'key': 'value', 'timestamp': DateTime.now().toIso8601String()},
        );
      }
    } catch (e) {
      // DioInterceptor catches errors automatically
      debugPrint('Request failed: $e');
    }
  }

  Future<void> _makeHttpRequest() async {
    try {
      // Use hardcoded URL for simple http demo, or construct from baseUrl
      final baseUrl =
          EasyDebugManager().currentEnvNotifier.value?.baseUrl ??
          'https://jsonplaceholder.typicode.com';
      final url = Uri.parse('$baseUrl/todos/1');
      await _httpClient.get(url);
    } catch (e) {
      debugPrint('Http Request failed: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Easy Debug Demo')),
      body: ListView(
        padding: const EdgeInsets.all(24),
        children: [
          _buildSectionHeader('Dio Requests'),
          ElevatedButton(
            onPressed: () => _makeRequest('/posts/1', 'GET'),
            child: const Text('GET Success (200)'),
          ),
          const SizedBox(height: 12),
          ElevatedButton(
            onPressed: () => _makeRequest('/posts', 'POST'),
            child: const Text('POST Success (201)'),
          ),
          const SizedBox(height: 12),
          ElevatedButton(
            onPressed: () => _makeRequest('/unknown-url', 'GET'),
            style: ElevatedButton.styleFrom(backgroundColor: Colors.orange),
            child: const Text('GET 404 Error'),
          ),
          const SizedBox(height: 12),
          ElevatedButton(
            onPressed: () => _makeRequest('https://invalid-domain.test', 'GET'),
            style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
            child: const Text('Connection Error'),
          ),

          const SizedBox(height: 32),
          _buildSectionHeader('Http Package Requests'),
          ElevatedButton(
            onPressed: _makeHttpRequest,
            style: ElevatedButton.styleFrom(backgroundColor: Colors.purple),
            child: const Text('Make http.Client Request'),
          ),

          const SizedBox(height: 32),
          _buildSectionHeader('General Logs'),
          ElevatedButton(
            onPressed: () {
              debugPrint('This is a test log at ${DateTime.now()}');
              print(
                'This print() might be captured if we used runZoned, but for now debugPrint is safer.',
              );
              debugPrint('Warning: This is a simulated warning message.');
              debugPrint('Error: This is a simulated error message!');
            },
            style: ElevatedButton.styleFrom(backgroundColor: Colors.grey),
            child: const Text('Print General Logs (Info/Warn/Error)'),
          ),

          const SizedBox(height: 32),
          _buildSectionHeader('Navigation'),
          ElevatedButton(
            onPressed: () {
              Navigator.of(
                context,
              ).push(MaterialPageRoute(builder: (_) => const SecondPage()));
            },
            child: const Text('Navigate to Second Page'),
          ),
        ],
      ),
    );
  }

  Widget _buildSectionHeader(String title) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 12),
      child: Text(
        title,
        style: const TextStyle(
          fontSize: 18,
          fontWeight: FontWeight.bold,
          color: Colors.black87,
        ),
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  const SecondPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Second Page")),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Dio().get('https://jsonplaceholder.typicode.com/comments?postId=1');
          },
          child: const Text("Make Request (No Interceptor)"),
        ),
      ),
    );
  }
}
2
likes
160
points
216
downloads

Publisher

unverified uploader

Weekly Downloads

A pure Dart in-app network debugger for Flutter. visualize Dio requests with a floating overlay, detailed inspection, and log management.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

dio, flutter, http, shared_preferences

More

Packages that depend on easy_debug