ispect 4.4.0-dev06 copy "ispect: ^4.4.0-dev06" to clipboard
ispect: ^4.4.0-dev06 copied to clipboard

Logging and inspector tool for Flutter development and testing

example/lib/main.dart

import 'dart:async';

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:http_interceptor/http_interceptor.dart' as http_interceptor;
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:ispect/ispect.dart';
import 'package:ispect_example/src/core/localization/generated/app_localizations.dart';
import 'package:ispect_example/src/cubit/test_cubit.dart';
import 'package:ispect_example/src/bloc/counter_bloc.dart';
import 'package:ispect_example/src/theme_manager.dart';
import 'package:ispect_example/src/ui/cards/parameters_card.dart';
import 'package:ispect_example/src/ui/cards/network_card.dart';
import 'package:ispect_example/src/ui/cards/logging_card.dart';
import 'package:ispect_example/src/ui/cards/state_management_card.dart';
import 'package:ispect_example/src/ui/cards/error_card.dart';
import 'package:ispect_example/src/ui/cards/stream_card.dart';
import 'package:ispect_example/src/services/log_generation_service.dart';
import 'package:ispect_example/src/riverpod/demo_settings_provider.dart';
import 'package:ispect_example/src/riverpod/providers.dart';

// Simple locale provider
final localeProvider = StateNotifierProvider<LocaleNotifier, Locale>((ref) {
  return LocaleNotifier();
});

class LocaleNotifier extends StateNotifier<Locale> {
  LocaleNotifier() : super(const Locale('en', 'US'));

  void setLocale(Locale locale) {
    state = locale;
  }

  void toggleLanguage() {
    state = state.languageCode == 'en'
        ? const Locale('ru', 'RU')
        : const Locale('en', 'US');
  }
}

final Dio dio = Dio(
  BaseOptions(
    baseUrl: 'https://jsonplaceholder.typicode.com',
  ),
);

final http_interceptor.InterceptedClient client =
    http_interceptor.InterceptedClient.build(interceptors: []);

final Dio dummyDio = Dio(
  BaseOptions(
    baseUrl: 'https://api.escuelajs.co',
  ),
);

void main() {
  ISpect.run(
    logger: ISpectifyFlutter.init(),
    () => runApp(
      ThemeProvider(
        child: ProviderScope(
          child: const MyApp(),
        ),
      ),
    ),
  );
}

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

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final themeMode = ThemeProvider.themeMode(context);
    final locale = ref.watch(localeProvider);

    return MaterialApp(
      title: 'ISpect Demo',
      theme: ThemeData.light(),
      darkTheme: ThemeData.dark(),
      themeMode: themeMode,
      locale: locale,
      localizationsDelegates: ISpectLocalizations.delegates(delegates: [
        ExampleGeneratedLocalization.delegate,
      ]),
      home: const Home(),
      builder: (context, child) {
        return ISpectBuilder(
          child: child!,
        );
      },
    );
  }
}

class Home extends ConsumerWidget {
  const Home({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final settings = ref.watch(demoSettingsProvider);
    final logService = ref.watch(logGenerationServiceProvider);
    final testCubit = ref.watch(testCubitProvider);
    final counterBloc = ref.watch(counterBlocProvider);
    final currentLocale = ref.watch(localeProvider);

    return Scaffold(
      appBar: AppBar(
        title: const Text('ISpect Demo'),
        actions: [
          IconButton(
            icon: Icon(
              ThemeProvider.themeMode(context) == ThemeMode.dark
                  ? Icons.light_mode
                  : Icons.dark_mode,
            ),
            onPressed: () => ThemeProvider.toggleTheme(context),
            tooltip: ThemeProvider.themeMode(context) == ThemeMode.dark
                ? 'Switch to Light Mode'
                : 'Switch to Dark Mode',
          ),
          IconButton(
            icon: Text(
              currentLocale.languageCode.toUpperCase(),
              style: const TextStyle(fontWeight: FontWeight.bold),
            ),
            onPressed: () => ref.read(localeProvider.notifier).toggleLanguage(),
            tooltip: 'Toggle Language',
          ),
          IconButton(
            icon: const Icon(Icons.language),
            onPressed: () => _showLanguageDialog(context, ref),
            tooltip: 'Change Language',
          ),
          IconButton(
            icon: const Icon(Icons.settings),
            onPressed: () => _showSettingsDialog(context, ref),
          ),
        ],
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            ParametersCard(
              requestCount: settings.requestCount,
              itemCount: settings.itemCount,
              nestingDepth: settings.nestingDepth,
              payloadSize: settings.payloadSize,
              wsMessageSize: settings.wsMessageSize,
              loopDelayMs: settings.loopDelayMs,
              httpMethod: settings.httpMethod,
              preset: settings.preset,
              useAuthHeader: settings.useAuthHeader,
              randomize: settings.randomize,
              onRequestCountChanged: (value) => ref
                  .read(demoSettingsProvider.notifier)
                  .updateRequestCount(value),
              onItemCountChanged: (value) => ref
                  .read(demoSettingsProvider.notifier)
                  .updateItemCount(value),
              onNestingDepthChanged: (value) => ref
                  .read(demoSettingsProvider.notifier)
                  .updateNestingDepth(value),
              onPayloadSizeChanged: (value) => ref
                  .read(demoSettingsProvider.notifier)
                  .updatePayloadSize(value),
              onWsMessageSizeChanged: (value) => ref
                  .read(demoSettingsProvider.notifier)
                  .updateWsMessageSize(value),
              onLoopDelayMsChanged: (value) => ref
                  .read(demoSettingsProvider.notifier)
                  .updateLoopDelayMs(value),
              onHttpMethodChanged: (value) => ref
                  .read(demoSettingsProvider.notifier)
                  .updateHttpMethod(value),
              onPresetChanged: (value) =>
                  ref.read(demoSettingsProvider.notifier).updatePreset(value),
              onUseAuthHeaderChanged: (value) => ref
                  .read(demoSettingsProvider.notifier)
                  .updateUseAuthHeader(value),
              onRandomizeChanged: (value) => ref
                  .read(demoSettingsProvider.notifier)
                  .updateRandomize(value),
            ),
            const SizedBox(height: 16),
            NetworkCard(
              enableHttp: settings.enableHttp,
              httpSendSuccess: settings.httpSendSuccess,
              httpSendErrors: settings.httpSendErrors,
              enableWs: settings.enableWs,
              enableFileUploads: settings.enableFileUploads,
              onEnableHttpChanged: (value) => ref
                  .read(demoSettingsProvider.notifier)
                  .updateEnableHttp(value),
              onHttpSendSuccessChanged: (value) => ref
                  .read(demoSettingsProvider.notifier)
                  .updateHttpSendSuccess(value),
              onHttpSendErrorsChanged: (value) => ref
                  .read(demoSettingsProvider.notifier)
                  .updateHttpSendErrors(value),
              onEnableWsChanged: (value) =>
                  ref.read(demoSettingsProvider.notifier).updateEnableWs(value),
              onEnableFileUploadsChanged: (value) => ref
                  .read(demoSettingsProvider.notifier)
                  .updateEnableFileUploads(value),
            ),
            const SizedBox(height: 16),
            LoggingCard(
              enableLogging: settings.enableLogging,
              enableAnalytics: settings.enableAnalytics,
              enableRoutes: settings.enableRoutes,
              onEnableLoggingChanged: (value) => ref
                  .read(demoSettingsProvider.notifier)
                  .updateEnableLogging(value),
              onEnableAnalyticsChanged: (value) => ref
                  .read(demoSettingsProvider.notifier)
                  .updateEnableAnalytics(value),
              onEnableRoutesChanged: (value) => ref
                  .read(demoSettingsProvider.notifier)
                  .updateEnableRoutes(value),
            ),
            const SizedBox(height: 16),
            StateManagementCard(
              enableBlocEvents: settings.enableBlocEvents,
              enableRiverpod: settings.enableRiverpod,
              onEnableBlocEventsChanged: (value) => ref
                  .read(demoSettingsProvider.notifier)
                  .updateEnableBlocEvents(value),
              onEnableRiverpodChanged: (value) => ref
                  .read(demoSettingsProvider.notifier)
                  .updateEnableRiverpod(value),
            ),
            const SizedBox(height: 16),
            ErrorCard(
              enableExceptions: settings.enableExceptions,
              onEnableExceptionsChanged: (value) => ref
                  .read(demoSettingsProvider.notifier)
                  .updateEnableExceptions(value),
            ),
            const SizedBox(height: 16),
            StreamCard(
              streamMode: settings.streamMode,
              intervalMs: settings.streamIntervalMs,
              onStreamModeChanged: (value) => ref
                  .read(demoSettingsProvider.notifier)
                  .updateStreamMode(value),
              onIntervalChanged: (value) => ref
                  .read(demoSettingsProvider.notifier)
                  .updateStreamIntervalMs(value),
            ),
            const SizedBox(height: 16),
            ElevatedButton(
              onPressed: () => _executeActions(
                  context, ref, logService, testCubit, counterBloc),
              child: const Text('Execute Actions'),
            ),
          ],
        ),
      ),
    );
  }

  void _showSettingsDialog(BuildContext context, WidgetRef ref) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Settings'),
        content: const Text('Settings dialog placeholder'),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(),
            child: const Text('Close'),
          ),
        ],
      ),
    );
  }

  void _showLanguageDialog(BuildContext context, WidgetRef ref) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Select Language'),
        content: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            ListTile(
              title: const Text('English'),
              onTap: () {
                ref
                    .read(localeProvider.notifier)
                    .setLocale(const Locale('en', 'US'));
                Navigator.of(context).pop();
              },
            ),
            ListTile(
              title: const Text('Русский'),
              onTap: () {
                ref
                    .read(localeProvider.notifier)
                    .setLocale(const Locale('ru', 'RU'));
                Navigator.of(context).pop();
              },
            ),
          ],
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(),
            child: const Text('Cancel'),
          ),
        ],
      ),
    );
  }

  Future<void> _executeActions(
    BuildContext context,
    WidgetRef ref,
    LogGenerationService logService,
    TestCubit testCubit,
    CounterBloc counterBloc,
  ) async {
    final settings = ref.read(demoSettingsProvider);

    if (settings.enableHttp) {
      await logService.generateHttpRequests(
        requestCount: settings.requestCount,
        httpMethod: settings.httpMethod,
        randomize: settings.randomize,
        useAuthHeader: settings.useAuthHeader,
        httpSendSuccess: settings.httpSendSuccess,
        httpSendErrors: settings.httpSendErrors,
        payloadSize: settings.payloadSize,
        loopDelayMs: settings.loopDelayMs,
      );
    }

    if (settings.enableWs) {
      await logService.generateWebSocketActions(
        itemCount: settings.itemCount,
        wsMessageSize: settings.wsMessageSize,
        randomize: settings.randomize,
        loopDelayMs: settings.loopDelayMs,
      );
    }

    if (settings.enableLogging) {
      await logService.generateLogs(
        itemCount: settings.itemCount,
        randomize: settings.randomize,
        loopDelayMs: settings.loopDelayMs,
        useAuthHeader: settings.useAuthHeader,
        httpSendSuccess: settings.httpSendSuccess,
        httpSendErrors: settings.httpSendErrors,
      );
    }

    if (settings.enableExceptions) {
      await logService.generateExceptions(
        requestCount: settings.requestCount,
      );
    }

    if (settings.enableFileUploads) {
      await logService.generateFileUploads(
        requestCount: settings.requestCount,
      );
    }

    if (settings.enableAnalytics) {
      await logService.generateAnalytics(
        itemCount: settings.itemCount,
      );
    }

    if (settings.enableRoutes) {
      await logService.generateRoutes(
        requestCount: settings.requestCount,
      );
    }

    if (settings.enableBlocEvents) {
      await logService.generateBlocEvents(
        itemCount: settings.itemCount,
        loopDelayMs: settings.loopDelayMs,
        testCubit: testCubit,
        counterBloc: counterBloc,
      );
    }

    if (settings.enableRiverpod) {
      await logService.generateRiverpodActions(
        itemCount: settings.itemCount,
        loopDelayMs: settings.loopDelayMs,
      );
    }
  }
}